summaryrefslogtreecommitdiff
authorsandman <sandman>2002-12-16 23:43:25 (UTC)
committer sandman <sandman>2002-12-16 23:43:25 (UTC)
commit79b94019014efe998b126219827f3050395beea7 (patch) (unidiff)
tree916c16dd21cc64fa98c0eed7042223d69efc27c4
parent3f28b7e0edb6115699b19f9db37b55f775b91dc7 (diff)
downloadopie-79b94019014efe998b126219827f3050395beea7.zip
opie-79b94019014efe998b126219827f3050395beea7.tar.gz
opie-79b94019014efe998b126219827f3050395beea7.tar.bz2
Finally the app-killer in the launcher works. TT solution was calling
ps with some special options, that busybox ps didn't provide. I'm now scanning /proc/<pid>/stat for the right process.
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--core/launcher/runningappbar.cpp125
-rw-r--r--core/launcher/runningappbar.h8
2 files changed, 82 insertions, 51 deletions
diff --git a/core/launcher/runningappbar.cpp b/core/launcher/runningappbar.cpp
index c8f45d5..3ac66f2 100644
--- a/core/launcher/runningappbar.cpp
+++ b/core/launcher/runningappbar.cpp
@@ -24,12 +24,15 @@
24// For "kill" 24// For "kill"
25#include <sys/types.h> 25#include <sys/types.h>
26#include <signal.h> 26#include <signal.h>
27#include <stdio.h>
28#include <stdlib.h>
27 29
30#include <qdir.h>
28#include <qtimer.h> 31#include <qtimer.h>
29#include <qpopupmenu.h> 32#include <qpopupmenu.h>
30#include <qmessagebox.h> 33#include <qmessagebox.h>
31#include <qpainter.h> 34#include <qpainter.h>
32#include "qprocess.h" 35#include <opie/oprocess.h>
33#include <qpe/qpeapplication.h> 36#include <qpe/qpeapplication.h>
34#include <qpe/applnk.h> 37#include <qpe/applnk.h>
35#include <qpe/qcopenvelope_qws.h> 38#include <qpe/qcopenvelope_qws.h>
@@ -45,9 +48,11 @@ RunningAppBar::RunningAppBar(QWidget* parent)
45 m_AppLnkSet = new AppLnkSet( QPEApplication::qpeDir() + "apps" ); 48 m_AppLnkSet = new AppLnkSet( QPEApplication::qpeDir() + "apps" );
46 49
47#ifdef QWS 50#ifdef QWS
51
48 connect(qwsServer, SIGNAL(newChannel(const QString&)), this, SLOT(newQcopChannel(const QString&))); 52 connect(qwsServer, SIGNAL(newChannel(const QString&)), this, SLOT(newQcopChannel(const QString&)));
49 connect(qwsServer, SIGNAL(removedChannel(const QString&)), this, SLOT(removedQcopChannel(const QString&))); 53 connect(qwsServer, SIGNAL(removedChannel(const QString&)), this, SLOT(removedQcopChannel(const QString&)));
50#endif 54#endif
55
51 QCopChannel* channel = new QCopChannel( "QPE/System", this ); 56 QCopChannel* channel = new QCopChannel( "QPE/System", this );
52 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)), 57 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)),
53 this, SLOT(received(const QCString&, const QByteArray&)) ); 58 this, SLOT(received(const QCString&, const QByteArray&)) );
@@ -55,10 +60,11 @@ RunningAppBar::RunningAppBar(QWidget* parent)
55 spacing = AppLnk::smallIconSize()+3; 60 spacing = AppLnk::smallIconSize()+3;
56} 61}
57 62
58RunningAppBar::~RunningAppBar() { 63RunningAppBar::~RunningAppBar()
59} 64{}
60 65
61void RunningAppBar::newQcopChannel(const QString& channelName) { 66void RunningAppBar::newQcopChannel(const QString& channelName)
67{
62 QString prefix("QPE/Application/"); 68 QString prefix("QPE/Application/");
63 if (channelName.startsWith(prefix)) { 69 if (channelName.startsWith(prefix)) {
64 QString appName = channelName.mid(prefix.length()); 70 QString appName = channelName.mid(prefix.length());
@@ -70,7 +76,8 @@ void RunningAppBar::newQcopChannel(const QString& channelName) {
70 } 76 }
71} 77}
72 78
73void RunningAppBar::removedQcopChannel(const QString& channelName) { 79void RunningAppBar::removedQcopChannel(const QString& channelName)
80{
74 QString prefix("QPE/Application/"); 81 QString prefix("QPE/Application/");
75 if (channelName.startsWith(prefix)) { 82 if (channelName.startsWith(prefix)) {
76 QString appName = channelName.mid(prefix.length()); 83 QString appName = channelName.mid(prefix.length());
@@ -82,7 +89,8 @@ void RunningAppBar::removedQcopChannel(const QString& channelName) {
82 } 89 }
83} 90}
84 91
85void RunningAppBar::received(const QCString& msg, const QByteArray& data) { 92void RunningAppBar::received(const QCString& msg, const QByteArray& data)
93{
86 // Since fast apps appear and disappear without disconnecting from their 94 // Since fast apps appear and disappear without disconnecting from their
87 // channel we need to watch for the showing/hiding events and update according. 95 // channel we need to watch for the showing/hiding events and update according.
88 QDataStream stream( data, IO_ReadOnly ); 96 QDataStream stream( data, IO_ReadOnly );
@@ -90,14 +98,16 @@ void RunningAppBar::received(const QCString& msg, const QByteArray& data) {
90 QString appName; 98 QString appName;
91 stream >> appName; 99 stream >> appName;
92 addTask(*m_AppLnkSet->findExec(appName)); 100 addTask(*m_AppLnkSet->findExec(appName));
93 } else if ( msg == "fastAppHiding(QString)") { 101 }
102 else if ( msg == "fastAppHiding(QString)") {
94 QString appName; 103 QString appName;
95 stream >> appName; 104 stream >> appName;
96 removeTask(*m_AppLnkSet->findExec(appName)); 105 removeTask(*m_AppLnkSet->findExec(appName));
97 } 106 }
98} 107}
99 108
100void RunningAppBar::addTask(const AppLnk& appLnk) { 109void RunningAppBar::addTask(const AppLnk& appLnk)
110{
101// qDebug("Added %s to app list.", appLnk.name().latin1()); 111// qDebug("Added %s to app list.", appLnk.name().latin1());
102 AppLnk* newApp = new AppLnk(appLnk); 112 AppLnk* newApp = new AppLnk(appLnk);
103 newApp->setExec(appLnk.exec()); 113 newApp->setExec(appLnk.exec());
@@ -105,13 +115,24 @@ void RunningAppBar::addTask(const AppLnk& appLnk) {
105 update(); 115 update();
106} 116}
107 117
108void RunningAppBar::removeTask(const AppLnk& appLnk) { 118void RunningAppBar::removeTask(const AppLnk& appLnk)
119{
109 unsigned int i = 0; 120 unsigned int i = 0;
110 for (; i < m_AppList.count() ; i++) { 121 for (; i < m_AppList.count() ; i++) {
111 AppLnk* target = m_AppList.at(i); 122 AppLnk* target = m_AppList.at(i);
112 if (target->exec() == appLnk.exec()) { 123 if (target->exec() == appLnk.exec()) {
113 qDebug("Removing %s from app list.", appLnk.name().latin1()); 124 qDebug("Removing %s from app list.", appLnk.name().latin1());
114 m_AppList.remove(); 125 m_AppList.remove();
126
127 // grab the keyboard back, in case the app crashed/forgot
128
129 QPEApplication *qpeapp = (QPEApplication *) qApp;
130
131 if ( appLnk.exec() == qpeapp-> keyboardGrabbedBy ( )) {
132 qDebug ( "grabbing keyboard back from %s", appLnk.name().latin1());
133 qpeapp-> grabKeyboard ( );
134 }
135
115 delete target; 136 delete target;
116 } 137 }
117 } 138 }
@@ -134,7 +155,8 @@ void RunningAppBar::mousePressEvent(QMouseEvent *e)
134 return; 155 return;
135 } 156 }
136 } 157 }
137 } else { 158 }
159 else {
138 break; 160 break;
139 } 161 }
140 } 162 }
@@ -197,7 +219,8 @@ QSize RunningAppBar::sizeHint() const
197const int AppMonitor::RAISE_TIMEOUT_MS = 500; 219const int AppMonitor::RAISE_TIMEOUT_MS = 500;
198 220
199AppMonitor::AppMonitor(const AppLnk& app, RunningAppBar& owner) 221AppMonitor::AppMonitor(const AppLnk& app, RunningAppBar& owner)
200 : QObject(0L), m_Owner(owner), m_App(app), m_PsProc(0L), m_AppKillerBox(0L) { 222 : QObject(0L), m_Owner(owner), m_App(app), m_AppKillerBox(0L)
223{
201 QCopChannel* channel = new QCopChannel( "QPE/System", this ); 224 QCopChannel* channel = new QCopChannel( "QPE/System", this );
202 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)), 225 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)),
203 this, SLOT(received(const QCString&, const QByteArray&)) ); 226 this, SLOT(received(const QCString&, const QByteArray&)) );
@@ -205,14 +228,16 @@ AppMonitor::AppMonitor(const AppLnk& app, RunningAppBar& owner)
205 m_Timer.start(RAISE_TIMEOUT_MS, TRUE); 228 m_Timer.start(RAISE_TIMEOUT_MS, TRUE);
206} 229}
207 230
208AppMonitor::~AppMonitor() { 231AppMonitor::~AppMonitor()
232{
209 if (m_AppKillerBox) { 233 if (m_AppKillerBox) {
210 delete m_AppKillerBox; 234 delete m_AppKillerBox;
211 m_AppKillerBox = 0L; 235 m_AppKillerBox = 0L;
212 } 236 }
213} 237}
214 238
215void AppMonitor::received(const QCString& msg, const QByteArray& data) { 239void AppMonitor::received(const QCString& msg, const QByteArray& data)
240{
216 QDataStream stream( data, IO_ReadOnly ); 241 QDataStream stream( data, IO_ReadOnly );
217 242
218 if (msg == "appRaised(QString)") { 243 if (msg == "appRaised(QString)") {
@@ -237,8 +262,8 @@ void AppMonitor::received(const QCString& msg, const QByteArray& data) {
237 } 262 }
238} 263}
239 264
240void AppMonitor::timerExpired() { 265void AppMonitor::timerExpired()
241 // qDebug("Checking in on %s", m_App.name().latin1()); 266{
242 // We store this incase the application responds while we're 267 // We store this incase the application responds while we're
243 // waiting for user input so we know not to delete ourselves. This 268 // waiting for user input so we know not to delete ourselves. This
244 // will be cleaned up in the destructor. 269 // will be cleaned up in the destructor.
@@ -249,43 +274,49 @@ void AppMonitor::timerExpired() {
249 QMessageBox::No | QMessageBox::Default, 274 QMessageBox::No | QMessageBox::Default,
250 QMessageBox::NoButton); 275 QMessageBox::NoButton);
251 if (m_AppKillerBox->exec() == QMessageBox::Yes) { 276 if (m_AppKillerBox->exec() == QMessageBox::Yes) {
252 // qDebug("Killing the app!!! Bwuhahahaha!"); 277 QDir proc ( "/proc/", "[0-9]*", QDir::Name | QDir::Reversed, QDir::Dirs );
253 m_PsProc = new QProcess(QString("ps")); 278 QStringList allprocs = proc. entryList ( );
254 m_PsProc->addArgument("h");
255 m_PsProc->addArgument("-C");
256 m_PsProc->addArgument(m_App.exec());
257 m_PsProc->addArgument("-o");
258 m_PsProc->addArgument("pid");
259 connect(m_PsProc, SIGNAL(processExited()), this, SLOT(psProcFinished()));
260 m_PsProc->start();
261 }
262 else {
263 // qDebug("Wuss..");
264 // WE DELETE OURSELVES HERE! Don't do anything else!!
265 delete this;
266 }
267}
268 279
269void AppMonitor::psProcFinished() { 280 pid_t mypid = ::getpid ( );
270 QString pid = m_PsProc->readLineStdout();
271 delete m_PsProc;
272 m_PsProc = 0L;
273 281
274 // qDebug("Killing app %s", pid.latin1()); 282 for ( QStringList::Iterator it = allprocs. begin ( ); it != allprocs. end ( ); ++it ) {
275 if (pid.isEmpty()) { 283 if (( *it ). toInt ( ) <= mypid ) // only interested in children
276 // Hmm.. did the application bail before we got there? 284 continue;
277 qDebug("AppMonitor: Tried to kill application %s but ps couldn't find it.", m_App.exec().latin1()); 285
278 } 286 QCString s = QString ( "/proc/" + *it + "/stat" ). local8Bit ( );
279 else { 287
280 int success = kill(pid.toUInt(), SIGKILL); 288 FILE *fp = ::fopen ( s. data ( ), "r" );
281 if (success == 0) { 289 if ( fp ) {
290 pid_t pid, ppid;
291 char *execptr, *exec = 0;
292
293 if ( ::fscanf ( fp, "%d %as %*c %d ", &pid, &execptr, &ppid ) == 3 ) {
294 exec = execptr [0] ? execptr + 1 : execptr;
295 if ( exec [0] )
296 exec [::strlen ( exec ) - 1] = 0;
297
298 if (( ppid == ::getpid ( )) && ( m_App. exec ( ). local8Bit ( ) == exec )) {
299 bool success = false;
300
301 qDebug ( "trying to kill pid=%d, exec=%s, ppid=%d", pid, exec, ppid );
302
303
304 success |= ( ::kill ( pid, SIGTERM ) == 0 );
305 ::usleep ( 1000 * 500 );
306 success |= ( ::kill ( pid, SIGKILL ) == 0 );
307
308 if ( success )
282 m_Owner.removeTask(m_App); 309 m_Owner.removeTask(m_App);
310
311 ::free ( execptr );
312 break;
313 }
314 ::free ( execptr );
315 }
316 ::fclose ( fp );
283 } 317 }
284 else {
285 qWarning("Could not kill task %s", m_App.exec().latin1());
286 } 318 }
287 } 319 }
288
289 // WE DELETE OURSELVES HERE! Don't do anything else!!
290 delete this; 320 delete this;
291} 321}
322
diff --git a/core/launcher/runningappbar.h b/core/launcher/runningappbar.h
index 880bb69..eb5880e 100644
--- a/core/launcher/runningappbar.h
+++ b/core/launcher/runningappbar.h
@@ -31,7 +31,8 @@ class QCString;
31class QProcess; 31class QProcess;
32class QMessageBox; 32class QMessageBox;
33 33
34class RunningAppBar : public QFrame { 34class RunningAppBar : public QFrame
35{
35 Q_OBJECT 36 Q_OBJECT
36 37
37 public: 38 public:
@@ -62,7 +63,8 @@ class RunningAppBar : public QFrame {
62 * to make sure the process is on top. If it's not it displays a dialog 63 * to make sure the process is on top. If it's not it displays a dialog
63 * box asking permission to kill it. 64 * box asking permission to kill it.
64 */ 65 */
65class AppMonitor : public QObject { 66class AppMonitor : public QObject
67{
66 Q_OBJECT 68 Q_OBJECT
67 69
68 public: 70 public:
@@ -74,13 +76,11 @@ class AppMonitor : public QObject {
74 private slots: 76 private slots:
75 void timerExpired(); 77 void timerExpired();
76 void received(const QCString& msg, const QByteArray& data); 78 void received(const QCString& msg, const QByteArray& data);
77 void psProcFinished();
78 79
79 private: 80 private:
80 RunningAppBar& m_Owner; 81 RunningAppBar& m_Owner;
81 const AppLnk& m_App; 82 const AppLnk& m_App;
82 QTimer m_Timer; 83 QTimer m_Timer;
83 QProcess* m_PsProc;
84 QMessageBox* m_AppKillerBox; 84 QMessageBox* m_AppKillerBox;
85}; 85};
86 86