summaryrefslogtreecommitdiff
path: root/core/launcher
Unidiff
Diffstat (limited to 'core/launcher') (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
@@ -21,18 +21,21 @@
21 21
22#define QTOPIA_INTERNAL_PRELOADACCESS 22#define QTOPIA_INTERNAL_PRELOADACCESS
23 23
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>
36#include <qpe/global.h> 39#include <qpe/global.h>
37#include <qwindowsystem_qws.h> 40#include <qwindowsystem_qws.h>
38#include "runningappbar.h" 41#include "runningappbar.h"
@@ -42,79 +45,97 @@ RunningAppBar::RunningAppBar(QWidget* parent)
42{ 45{
43 setBackgroundMode( PaletteBackground ); 46 setBackgroundMode( PaletteBackground );
44 47
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&)) );
54 59
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());
65// qDebug("App %s just connected!", appName.latin1()); 71// qDebug("App %s just connected!", appName.latin1());
66 const AppLnk* newGuy = m_AppLnkSet->findExec(appName); 72 const AppLnk* newGuy = m_AppLnkSet->findExec(appName);
67 if (newGuy && !newGuy->isPreloaded()) { 73 if (newGuy && !newGuy->isPreloaded()) {
68 addTask(*newGuy); 74 addTask(*newGuy);
69 } 75 }
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());
77 qDebug("App %s just disconnected!", appName.latin1()); 84 qDebug("App %s just disconnected!", appName.latin1());
78 const AppLnk* newGuy = m_AppLnkSet->findExec(appName); 85 const AppLnk* newGuy = m_AppLnkSet->findExec(appName);
79 if (newGuy) { 86 if (newGuy) {
80 removeTask(*newGuy); 87 removeTask(*newGuy);
81 } 88 }
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 );
89 if ( msg == "fastAppShowing(QString)") { 97 if ( msg == "fastAppShowing(QString)") {
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());
104 m_AppList.prepend(newApp); 114 m_AppList.prepend(newApp);
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 }
118 update(); 139 update();
119} 140}
120 141
@@ -131,13 +152,14 @@ void RunningAppBar::mousePressEvent(QMouseEvent *e)
131 if ( e->x() >= x && e->x() < x+spacing ) { 152 if ( e->x() >= x && e->x() < x+spacing ) {
132 if ( m_SelectedAppIndex < (int)m_AppList.count() ) { 153 if ( m_SelectedAppIndex < (int)m_AppList.count() ) {
133 repaint(FALSE); 154 repaint(FALSE);
134 return; 155 return;
135 } 156 }
136 } 157 }
137 } else { 158 }
159 else {
138 break; 160 break;
139 } 161 }
140 } 162 }
141 m_SelectedAppIndex = -1; 163 m_SelectedAppIndex = -1;
142 repaint( FALSE ); 164 repaint( FALSE );
143} 165}
@@ -194,28 +216,31 @@ QSize RunningAppBar::sizeHint() const
194 return QSize( frameWidth(), AppLnk::smallIconSize()+frameWidth()*2+3 ); 216 return QSize( frameWidth(), AppLnk::smallIconSize()+frameWidth()*2+3 );
195} 217}
196 218
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&)) );
204 connect(&m_Timer, SIGNAL(timeout()), this, SLOT(timerExpired())); 227 connect(&m_Timer, SIGNAL(timeout()), this, SLOT(timerExpired()));
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)") {
219 QString appName; 244 QString appName;
220 stream >> appName; 245 stream >> appName;
221 if (appName == m_App.exec()) { 246 if (appName == m_App.exec()) {
@@ -234,58 +259,64 @@ void AppMonitor::received(const QCString& msg, const QByteArray& data) {
234 delete this; 259 delete this;
235 } 260 }
236 } 261 }
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.
245 m_AppKillerBox = new QMessageBox(tr("Application Problem"), 270 m_AppKillerBox = new QMessageBox(tr("Application Problem"),
246 tr("<p>%1 is not responding.</p>").arg(m_App.name()) + 271 tr("<p>%1 is not responding.</p>").arg(m_App.name()) +
247 tr("<p>Would you like to force the application to exit?</p>"), 272 tr("<p>Would you like to force the application to exit?</p>"),
248 QMessageBox::Warning, QMessageBox::Yes, 273 QMessageBox::Warning, QMessageBox::Yes,
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
@@ -28,13 +28,14 @@
28class AppLnk; 28class AppLnk;
29class AppLnkSet; 29class AppLnkSet;
30class QCString; 30class 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:
38 RunningAppBar(QWidget* parent); 39 RunningAppBar(QWidget* parent);
39 ~RunningAppBar(); 40 ~RunningAppBar();
40 41
@@ -59,30 +60,29 @@ class RunningAppBar : public QFrame {
59 60
60/** 61/**
61 * Internal class that checks back in on the process when timerExpired is called 62 * Internal class that checks back in on the process when timerExpired is called
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:
69 static const int RAISE_TIMEOUT_MS; 71 static const int RAISE_TIMEOUT_MS;
70 72
71 AppMonitor(const AppLnk& app, RunningAppBar& owner); 73 AppMonitor(const AppLnk& app, RunningAppBar& owner);
72 ~AppMonitor(); 74 ~AppMonitor();
73 75
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
87#endif 87#endif
88 88