[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    [PATCH] Turn Powerdevil suspend notification into a dialog
From:       Aurélien Gâteau <aurelien.gateau () canonical ! com>
Date:       2009-09-22 12:19:57
Message-ID: 4AB8C0ED.60402 () canonical ! com
[Download RAW message or body]

Hi,

In case you missed it, an earlier discussion about notification 
capabilities on this list diverged a bit on Powerdevil suspend 
notification. I am referring to the notification which appears when your 
laptop is running out of battery. Powerdevil shows a notification to 
tell you it will suspend the machine in a few seconds, unless you click 
the "Cancel" button of the notification.

I believe this is one of the few cases where using a dialog is more 
appropriate than using a notification because the system is about to do 
something very drastic, so it should ensure the user does not miss it.

The dialog approach has a drawback though: it can steal the focus, 
resulting in the user accidentally triggering one of the dialog buttons 
if the dialog receive a keystroke intended for the previously active window.

Attached first patch turns Powerdevil suspend notification into a 
dialog. To avoid the focus-stealing problem it opens the dialog as 
always-on-top and on all desktops, but keeps the previously active 
window active. I have been running it for a while without problems.

It also adds a few niceties:
- A button to trigger the action right now.
- A real-time updated count down in the dialog text, so that the user 
knows in real time how much time is left.

Here is a screenshot of the dialog:
http://imagebin.ca/view/OT7MHYEn.html

(Unfortunately updating the text of a KMessageBox is not possible at 
runtime, so I had to create a KDialog-based dialog. This could be fixed 
by giving an object name to the text label created by KMessageBox)

The second patch increases the default timeout from 10 seconds to 30 
seconds, giving the user more time to react.

What do you think about this?

Aurelien

["0001-Turn-low-battery-notifications-into-a-countdown-dial.patch" (text/x-diff)]

From 64b0a6eb0eda9d209b18509d032204314b4c4dcd Mon Sep 17 00:00:00 2001
From: Aurelien Gateau <aurelien.gateau@canonical.com>
Date: Tue, 22 Sep 2009 10:25:59 +0200
Subject: [PATCH 1/2] Turn low battery notifications into a countdown dialog

---
 workspace/powerdevil/daemon/CMakeLists.txt       |    1 +
 workspace/powerdevil/daemon/CountDownDialog.cpp  |  124 ++++++++++++++++++++++
 workspace/powerdevil/daemon/CountDownDialog.h    |   49 +++++++++
 workspace/powerdevil/daemon/PowerDevilDaemon.cpp |  116 ++++++++++----------
 workspace/powerdevil/daemon/PowerDevilDaemon.h   |    4 +
 5 files changed, 236 insertions(+), 58 deletions(-)
 create mode 100644 workspace/powerdevil/daemon/CountDownDialog.cpp
 create mode 100644 workspace/powerdevil/daemon/CountDownDialog.h

diff --git a/workspace/powerdevil/daemon/CMakeLists.txt \
b/workspace/powerdevil/daemon/CMakeLists.txt index 970315e..7df020c 100644
--- a/workspace/powerdevil/daemon/CMakeLists.txt
+++ b/workspace/powerdevil/daemon/CMakeLists.txt
@@ -7,6 +7,7 @@ set( kded_powerdevil_SRCS
     PowerDevilDaemon.cpp
     SuspensionLockHandler.cpp
     PowerManagementConnector.cpp
+    CountDownDialog.cpp
 )
 
 kde4_add_kcfg_files(kded_powerdevil_SRCS ../PowerDevilSettings.kcfgc)
diff --git a/workspace/powerdevil/daemon/CountDownDialog.cpp \
b/workspace/powerdevil/daemon/CountDownDialog.cpp new file mode 100644
index 0000000..dd206e9
--- /dev/null
+++ b/workspace/powerdevil/daemon/CountDownDialog.cpp
@@ -0,0 +1,124 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Canonical Ltd                                   *
+ *   Author: Aurélien Gâteau <aurelien.gateau@canonical.com>               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
+ ***************************************************************************/
+#include "CountDownDialog.h"
+
+#include <KLocale>
+#include <KPushButton>
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QTimer>
+
+CountDownDialog::CountDownDialog(PowerDevilDaemon::IdleAction action, int countDown)
+: m_action(action)
+, m_countDown(countDown)
+{
+    KIcon icon = KIcon("battery-low");
+    setWindowIcon(icon);
+
+    setCaption(i18n("Battery Level is Critical"));
+
+    QLabel *iconLabel = new QLabel;
+    iconLabel->setPixmap(icon.pixmap(KIconLoader::SizeLarge, \
KIconLoader::SizeLarge)); +    iconLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+    iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+    m_label = new QLabel;
+    m_label->setWordWrap(true);
+
+    QWidget *mainWidget = new QWidget;
+    QHBoxLayout *layout = new QHBoxLayout(mainWidget);
+    layout->setMargin(0);
+    layout->setSpacing(KDialog::spacingHint());
+    layout->addWidget(iconLabel);
+    layout->addWidget(m_label);
+    setMainWidget(mainWidget);
+
+    setButtons(KDialog::Cancel | KDialog::Ok);
+
+    KGuiItem item;
+    switch (action) {
+    case PowerDevilDaemon::Shutdown:
+        item = KGuiItem(i18n("Shutdown"), "system-shutdown");
+        break;
+    case PowerDevilDaemon::S2Disk:
+        item = KGuiItem(i18n("Suspend to Disk"), "system-suspend-hibernate");
+        break;
+    case PowerDevilDaemon::S2Ram:
+        item = KGuiItem(i18n("Suspend to RAM"), "system-suspend");
+        break;
+    case PowerDevilDaemon::Standby:
+        item = KGuiItem(i18n("Standby"));
+        break;
+    default:
+        Q_ASSERT(false);
+        break;
+    }
+    setButtonGuiItem(KDialog::Ok, item);
+
+    updateText();
+
+    QTimer *timer = new QTimer(this);
+    timer->setInterval(1000);
+    connect(timer, SIGNAL(timeout()), SLOT(decreaseCountDown()));
+    timer->start();
+}
+
+void CountDownDialog::decreaseCountDown()
+{
+    --m_countDown;
+    updateText();
+    if (m_countDown == 0) {
+        button(KDialog::Ok)->click();
+    }
+}
+
+void CountDownDialog::updateText()
+{
+    QString text;
+    switch (m_action) {
+    case PowerDevilDaemon::Shutdown:
+        text = i18np("Your battery level is critical, the computer will be halted in \
1 second.", +                "Your battery level is critical, the computer will be \
halted in %1 seconds.", +                m_countDown);
+        break;
+    case PowerDevilDaemon::S2Disk:
+        text = i18np("Your battery level is critical, the computer will be suspended \
to disk in 1 second.", +                "Your battery level is critical, the computer \
will be suspended to disk in %1 seconds.", +                m_countDown);
+        break;
+    case PowerDevilDaemon::S2Ram:
+        text = i18np("Your battery level is critical, the computer will be suspended \
to RAM in 1 second.", +                "Your battery level is critical, the computer \
will be suspended to RAM in %1 seconds.", +                m_countDown);
+        break;
+    case PowerDevilDaemon::Standby:
+        text = i18np("Your battery level is critical, the computer will be put into \
standby in 1 second.", +                "Your battery level is critical, the computer \
will be put into standby in %1 seconds.", +                m_countDown);
+        break;
+    default:
+        Q_ASSERT(false);
+        break;
+    }
+    m_label->setText(text);
+}
+
+#include "CountDownDialog.moc"
diff --git a/workspace/powerdevil/daemon/CountDownDialog.h \
b/workspace/powerdevil/daemon/CountDownDialog.h new file mode 100644
index 0000000..856bebf
--- /dev/null
+++ b/workspace/powerdevil/daemon/CountDownDialog.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *   Copyright (C) 2009 by Canonical Ltd                                   *
+ *   Author: Aurélien Gâteau <aurelien.gateau@canonical.com>               *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
+ ***************************************************************************/
+#ifndef COUNTDOWNDIALOG_H
+#define COUNTDOWNDIALOG_H
+
+#include <KDialog>
+
+#include "PowerDevilDaemon.h"
+
+class QLabel;
+
+/**
+ * A dialog showing a count down message before auto-accepting itself
+ */
+class CountDownDialog : public KDialog
+{
+Q_OBJECT
+public:
+    CountDownDialog(PowerDevilDaemon::IdleAction action, int countDown);
+
+private Q_SLOTS:
+    void decreaseCountDown();
+
+private:
+    void updateText();
+
+    PowerDevilDaemon::IdleAction m_action;
+    QLabel *m_label;
+    int m_countDown;
+};
+
+#endif /* COUNTDOWNDIALOG_H */
diff --git a/workspace/powerdevil/daemon/PowerDevilDaemon.cpp \
b/workspace/powerdevil/daemon/PowerDevilDaemon.cpp index 11910dc..5daac70 100644
--- a/workspace/powerdevil/daemon/PowerDevilDaemon.cpp
+++ b/workspace/powerdevil/daemon/PowerDevilDaemon.cpp
@@ -36,11 +36,13 @@
 #include <kworkspace/kworkspace.h>
 #include <KApplication>
 #include <kidletime.h>
+#include <KWindowSystem>
 
 #include <QPointer>
 #include <QWidget>
 #include <QTimer>
 
+#include "CountDownDialog.h"
 #include "PowerDevilSettings.h"
 #include "powerdeviladaptor.h"
 #include "PowerManagementConnector.h"
@@ -478,64 +480,10 @@ void PowerDevilDaemon::batteryChargePercentChanged(int percent, \
const QString &u  }
 
     if (charge <= PowerDevilSettings::batteryCriticalLevel()) {
-        switch (PowerDevilSettings::batLowAction()) {
-        case Shutdown:
-            if (PowerDevilSettings::waitBeforeSuspending()) {
-                emitNotification("criticalbattery",
-                                 i18np("Your battery level is critical, the computer \
                will "
-                                       "be halted in 1 second.",
-                                       "Your battery level is critical, the computer \
                will "
-                                       "be halted in %1 seconds.",
-                                       \
                PowerDevilSettings::waitBeforeSuspendingTime()),
-                                 SLOT(shutdown()), "dialog-warning");
-            } else {
-                shutdown();
-            }
-            break;
-        case S2Disk:
-            if (PowerDevilSettings::waitBeforeSuspending()) {
-                emitNotification("criticalbattery",
-                                 i18np("Your battery level is critical, the computer \
                will "
-                                       "be suspended to disk in 1 second.",
-                                       "Your battery level is critical, the computer \
                will "
-                                       "be suspended to disk in %1 seconds.",
-                                       \
                PowerDevilSettings::waitBeforeSuspendingTime()),
-                                 SLOT(suspendToDisk()), "dialog-warning");
-            } else {
-                suspendToDisk();
-            }
-            break;
-        case S2Ram:
-            if (PowerDevilSettings::waitBeforeSuspending()) {
-                emitNotification("criticalbattery",
-                                 i18np("Your battery level is critical, the computer \
                "
-                                       "will be suspended to RAM in 1 second.",
-                                       "Your battery level is critical, the computer \
                "
-                                       "will be suspended to RAM in %1 seconds.",
-                                       \
                PowerDevilSettings::waitBeforeSuspendingTime()),
-                                 SLOT(suspendToRam()), "dialog-warning");
-            } else {
-                suspendToRam();
-            }
-            break;
-        case Standby:
-            if (PowerDevilSettings::waitBeforeSuspending()) {
-                emitNotification("criticalbattery",
-                                 i18np("Your battery level is critical, the computer \
                "
-                                       "will be put into standby in 1 second.",
-                                       "Your battery level is critical, the computer \
                "
-                                       "will be put into standby in %1 seconds.",
-                                       \
                PowerDevilSettings::waitBeforeSuspendingTime()),
-                                 SLOT(standby()), "dialog-warning");
-            } else {
-                standby();
-            }
-            break;
-        default:
-            emitNotification("criticalbattery", i18n("Your battery level is \
                critical: "
-                                                     "save your work as soon as \
                possible."),
-                             0, "dialog-warning");
-            break;
+        if (PowerDevilSettings::waitBeforeSuspending()) {
+            showCountDownDialog();
+        } else {
+            triggerBatLowAction();
         }
     } else if (charge == PowerDevilSettings::batteryWarningLevel()) {
         emitNotification("warningbattery", i18n("Your battery has reached the \
warning level."), @@ -548,6 +496,58 @@ void \
PowerDevilDaemon::batteryChargePercentChanged(int percent, const QString &u  }
 }
 
+void PowerDevilDaemon::triggerBatLowAction()
+{
+    switch (PowerDevilSettings::batLowAction()) {
+    case Shutdown:
+        shutdown();
+        break;
+    case S2Disk:
+        suspendToDisk();
+        break;
+    case S2Ram:
+        suspendToRam();
+        break;
+    case Standby:
+        standby();
+        break;
+    default:
+        emitNotification("criticalbattery", i18n("Your battery level is critical: "
+                                                 "save your work as soon as \
possible."), +                         0, "dialog-warning");
+        break;
+    }
+}
+
+void PowerDevilDaemon::showCountDownDialog()
+{
+    PowerDevilDaemon::IdleAction action = \
static_cast<PowerDevilDaemon::IdleAction>(PowerDevilSettings::batLowAction()); +    \
switch (action) { +    case Shutdown:
+    case S2Disk:
+    case S2Ram:
+    case Standby: {
+        CountDownDialog *dlg = new CountDownDialog(action, \
PowerDevilSettings::waitBeforeSuspendingTime()); +        connect(dlg, \
SIGNAL(accepted()), SLOT(triggerBatLowAction())); +        \
dlg->setAttribute(Qt::WA_DeleteOnClose, true); +
+        // Show the dialog on top, but keep current active window activated
+        dlg->setWindowFlags(dlg->windowFlags() | Qt::WindowStaysOnTopHint);
+        int oldWid = KWindowSystem::activeWindow();
+        dlg->show();
+        KWindowSystem::setOnAllDesktops(dlg->winId(), true);
+        if (oldWid) {
+            KWindowSystem::forceActiveWindow(oldWid);
+        }
+        break;
+    }
+    default:
+        // Will show warning
+        triggerBatLowAction();
+        break;
+    }
+}
+
 void PowerDevilDaemon::buttonPressed(int but)
 {
     if (!checkIfCurrentSessionActive() || d->screenSaverIface->GetActive()) {
diff --git a/workspace/powerdevil/daemon/PowerDevilDaemon.h \
b/workspace/powerdevil/daemon/PowerDevilDaemon.h index bff900f..b0f60bb 100644
--- a/workspace/powerdevil/daemon/PowerDevilDaemon.h
+++ b/workspace/powerdevil/daemon/PowerDevilDaemon.h
@@ -100,6 +100,8 @@ private Q_SLOTS:
 
     void batteryRemainingTimeChanged(int time);
 
+    void triggerBatLowAction();
+
 Q_SIGNALS:
     void lidClosed(int code, const QString &action);
     void errorTriggered(const QString &error);
@@ -128,6 +130,8 @@ private:
 
     bool checkIfCurrentSessionActive();
 
+    void showCountDownDialog();
+
 public:
     enum IdleAction {
         None = 0,
-- 
1.6.3.3


["0002-Increase-WaitBeforeSuspendingTime-from-10-to-30-seco.patch" (text/x-diff)]

From 0d89c6ac98973a48b2b14afa8ceba179e9ecb4b8 Mon Sep 17 00:00:00 2001
From: Aurelien Gateau <aurelien.gateau@canonical.com>
Date: Tue, 22 Sep 2009 10:42:18 +0200
Subject: [PATCH 2/2] Increase WaitBeforeSuspendingTime from 10 to 30 seconds

Gives more time for the user to handle the message.
---
 workspace/powerdevil/PowerDevilSettings.kcfg |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/workspace/powerdevil/PowerDevilSettings.kcfg b/workspace/powerdevil/PowerDevilSettings.kcfg
index 816abdd..f6dfe19 100644
--- a/workspace/powerdevil/PowerDevilSettings.kcfg
+++ b/workspace/powerdevil/PowerDevilSettings.kcfg
@@ -32,7 +32,7 @@
       <default>true</default>
     </entry>
     <entry name="WaitBeforeSuspendingTime" type="Int">
-      <default>10</default>
+      <default>30</default>
     </entry>
     <entry name="PollingSystem" type="Int">
       <default>-1</default>
-- 
1.6.3.3



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic