summaryrefslogtreecommitdiff
path: root/core/launcher/runningappbar.cpp
authorsandman <sandman>2002-12-16 23:43:25 (UTC)
committer sandman <sandman>2002-12-16 23:43:25 (UTC)
commit79b94019014efe998b126219827f3050395beea7 (patch) (unidiff)
tree916c16dd21cc64fa98c0eed7042223d69efc27c4 /core/launcher/runningappbar.cpp
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 (limited to 'core/launcher/runningappbar.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/runningappbar.cpp441
1 files changed, 236 insertions, 205 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>
@@ -38,254 +41,282 @@
38#include "runningappbar.h" 41#include "runningappbar.h"
39 42
40RunningAppBar::RunningAppBar(QWidget* parent) 43RunningAppBar::RunningAppBar(QWidget* parent)
41 : QFrame(parent), m_AppLnkSet(0L), m_SelectedAppIndex(-1) 44 : QFrame(parent), m_AppLnkSet(0L), m_SelectedAppIndex( -1)
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
48 connect(qwsServer, SIGNAL(newChannel(const QString&)), this, SLOT(newQcopChannel(const QString&))); 51
49 connect(qwsServer, SIGNAL(removedChannel(const QString&)), this, SLOT(removedQcopChannel(const QString&))); 52 connect(qwsServer, SIGNAL(newChannel(const QString&)), this, SLOT(newQcopChannel(const QString&)));
53 connect(qwsServer, SIGNAL(removedChannel(const QString&)), this, SLOT(removedQcopChannel(const QString&)));
50#endif 54#endif
51 QCopChannel* channel = new QCopChannel( "QPE/System", this );
52 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)),
53 this, SLOT(received(const QCString&, const QByteArray&)) );
54 55
55 spacing = AppLnk::smallIconSize()+3; 56 QCopChannel* channel = new QCopChannel( "QPE/System", this );
56} 57 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)),
58 this, SLOT(received(const QCString&, const QByteArray&)) );
57 59
58RunningAppBar::~RunningAppBar() { 60 spacing = AppLnk::smallIconSize() + 3;
59} 61}
60 62
61void RunningAppBar::newQcopChannel(const QString& channelName) { 63RunningAppBar::~RunningAppBar()
62 QString prefix("QPE/Application/"); 64{}
63 if (channelName.startsWith(prefix)) { 65
64 QString appName = channelName.mid(prefix.length()); 66void RunningAppBar::newQcopChannel(const QString& channelName)
65// qDebug("App %s just connected!", appName.latin1()); 67{
66 const AppLnk* newGuy = m_AppLnkSet->findExec(appName); 68 QString prefix("QPE/Application/");
67 if (newGuy && !newGuy->isPreloaded()) { 69 if (channelName.startsWith(prefix)) {
68 addTask(*newGuy); 70 QString appName = channelName.mid(prefix.length());
69 } 71 // qDebug("App %s just connected!", appName.latin1());
70 } 72 const AppLnk* newGuy = m_AppLnkSet->findExec(appName);
73 if (newGuy && !newGuy->isPreloaded()) {
74 addTask(*newGuy);
75 }
76 }
71} 77}
72 78
73void RunningAppBar::removedQcopChannel(const QString& channelName) { 79void RunningAppBar::removedQcopChannel(const QString& channelName)
74 QString prefix("QPE/Application/"); 80{
75 if (channelName.startsWith(prefix)) { 81 QString prefix("QPE/Application/");
76 QString appName = channelName.mid(prefix.length()); 82 if (channelName.startsWith(prefix)) {
77 qDebug("App %s just disconnected!", appName.latin1()); 83 QString appName = channelName.mid(prefix.length());
78 const AppLnk* newGuy = m_AppLnkSet->findExec(appName); 84 qDebug("App %s just disconnected!", appName.latin1());
79 if (newGuy) { 85 const AppLnk* newGuy = m_AppLnkSet->findExec(appName);
80 removeTask(*newGuy); 86 if (newGuy) {
81 } 87 removeTask(*newGuy);
82 } 88 }
89 }
83} 90}
84 91
85void RunningAppBar::received(const QCString& msg, const QByteArray& data) { 92void RunningAppBar::received(const QCString& msg, const QByteArray& data)
86 // Since fast apps appear and disappear without disconnecting from their 93{
87 // channel we need to watch for the showing/hiding events and update according. 94 // Since fast apps appear and disappear without disconnecting from their
88 QDataStream stream( data, IO_ReadOnly ); 95 // channel we need to watch for the showing/hiding events and update according.
89 if ( msg == "fastAppShowing(QString)") { 96 QDataStream stream( data, IO_ReadOnly );
90 QString appName; 97 if ( msg == "fastAppShowing(QString)") {
91 stream >> appName; 98 QString appName;
92 addTask(*m_AppLnkSet->findExec(appName)); 99 stream >> appName;
93 } else if ( msg == "fastAppHiding(QString)") { 100 addTask(*m_AppLnkSet->findExec(appName));
94 QString appName; 101 }
95 stream >> appName; 102 else if ( msg == "fastAppHiding(QString)") {
96 removeTask(*m_AppLnkSet->findExec(appName)); 103 QString appName;
97 } 104 stream >> appName;
105 removeTask(*m_AppLnkSet->findExec(appName));
106 }
98} 107}
99 108
100void RunningAppBar::addTask(const AppLnk& appLnk) { 109void RunningAppBar::addTask(const AppLnk& appLnk)
101// qDebug("Added %s to app list.", appLnk.name().latin1()); 110{
102 AppLnk* newApp = new AppLnk(appLnk); 111 // qDebug("Added %s to app list.", appLnk.name().latin1());
103 newApp->setExec(appLnk.exec()); 112 AppLnk* newApp = new AppLnk(appLnk);
104 m_AppList.prepend(newApp); 113 newApp->setExec(appLnk.exec());
105 update(); 114 m_AppList.prepend(newApp);
115 update();
106} 116}
107 117
108void RunningAppBar::removeTask(const AppLnk& appLnk) { 118void RunningAppBar::removeTask(const AppLnk& appLnk)
109 unsigned int i = 0; 119{
110 for (; i < m_AppList.count() ; i++) { 120 unsigned int i = 0;
111 AppLnk* target = m_AppList.at(i); 121 for (; i < m_AppList.count() ; i++) {
112 if (target->exec() == appLnk.exec()) { 122 AppLnk* target = m_AppList.at(i);
113 qDebug("Removing %s from app list.", appLnk.name().latin1()); 123 if (target->exec() == appLnk.exec()) {
114 m_AppList.remove(); 124 qDebug("Removing %s from app list.", appLnk.name().latin1());
115 delete target; 125 m_AppList.remove();
116 } 126
117 } 127 // grab the keyboard back, in case the app crashed/forgot
118 update(); 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
136 delete target;
137 }
138 }
139 update();
119} 140}
120 141
121void RunningAppBar::mousePressEvent(QMouseEvent *e) 142void RunningAppBar::mousePressEvent(QMouseEvent *e)
122{ 143{
123 // Find out if the user is clicking on an app icon... 144 // Find out if the user is clicking on an app icon...
124 // If so, snag the index so when we repaint we show it 145 // If so, snag the index so when we repaint we show it
125 // as highlighed. 146 // as highlighed.
126 m_SelectedAppIndex = 0; 147 m_SelectedAppIndex = 0;
127 int x=0; 148 int x = 0;
128 QListIterator<AppLnk> it( m_AppList ); 149 QListIterator<AppLnk> it( m_AppList );
129 for ( ; it.current(); ++it,++m_SelectedAppIndex,x+=spacing ) { 150 for ( ; it.current(); ++it, ++m_SelectedAppIndex, x += spacing ) {
130 if ( x + spacing <= width() ) { 151 if ( x + spacing <= width() ) {
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 ;
156 }
157 }
158 }
159 else {
160 break;
161 }
135 } 162 }
136 } 163 m_SelectedAppIndex = -1;
137 } else { 164 repaint( FALSE );
138 break;
139 }
140 }
141 m_SelectedAppIndex = -1;
142 repaint( FALSE );
143} 165}
144 166
145void RunningAppBar::mouseReleaseEvent(QMouseEvent *e) 167void RunningAppBar::mouseReleaseEvent(QMouseEvent *e)
146{ 168{
147 if (e->button() == QMouseEvent::RightButton) { 169 if (e->button() == QMouseEvent::RightButton) {
148 return; 170 return ;
149 } 171 }
150 if ( m_SelectedAppIndex >= 0 ) { 172 if ( m_SelectedAppIndex >= 0 ) {
151 QString channel = QString("QPE/Application/") + m_AppList.at(m_SelectedAppIndex)->exec(); 173 QString channel = QString("QPE/Application/") + m_AppList.at(m_SelectedAppIndex)->exec();
152 if (QCopChannel::isRegistered(channel.latin1())) { 174 if (QCopChannel::isRegistered(channel.latin1())) {
153// qDebug("%s is running!", m_AppList.at(m_SelectedAppIndex)->exec().latin1()); 175 // qDebug("%s is running!", m_AppList.at(m_SelectedAppIndex)->exec().latin1());
154 QCopEnvelope e(channel.latin1(), "raise()"); 176 QCopEnvelope e(channel.latin1(), "raise()");
155 // This class will delete itself after hearing from the app or the timer expiring 177 // This class will delete itself after hearing from the app or the timer expiring
156 (void)new AppMonitor(*m_AppList.at(m_SelectedAppIndex), *this); 178 (void)new AppMonitor(*m_AppList.at(m_SelectedAppIndex), *this);
157 } 179 }
158 else { 180 else {
159 removeTask(*m_AppList.at(m_SelectedAppIndex)); 181 removeTask(*m_AppList.at(m_SelectedAppIndex));
160 } 182 }
161 183
162 m_SelectedAppIndex = -1; 184 m_SelectedAppIndex = -1;
163 update(); 185 update();
164 } 186 }
165} 187}
166 188
167void RunningAppBar::paintEvent( QPaintEvent * ) 189void RunningAppBar::paintEvent( QPaintEvent * )
168{ 190{
169 QPainter p( this ); 191 QPainter p( this );
170 AppLnk *curApp; 192 AppLnk *curApp;
171 int x = 0; 193 int x = 0;
172 int y = (height() - AppLnk::smallIconSize()) / 2; 194 int y = (height() - AppLnk::smallIconSize()) / 2;
173 int i = 0; 195 int i = 0;
174 196
175 //p.fillRect( 0, 0, width(), height(), colorGroup().background() ); 197 //p.fillRect( 0, 0, width(), height(), colorGroup().background() );
176 198
177 QListIterator<AppLnk> it(m_AppList); 199 QListIterator<AppLnk> it(m_AppList);
178 200
179 for (; it.current(); i++, ++it ) { 201 for (; it.current(); i++, ++it ) {
180 if ( x + spacing <= width() ) { 202 if ( x + spacing <= width() ) {
181 curApp = it.current(); 203 curApp = it.current();
182 if ( (int)i == m_SelectedAppIndex ) 204 if ( (int)i == m_SelectedAppIndex )
183 p.fillRect( x, y, spacing, curApp->pixmap().height()+1, colorGroup().highlight() ); 205 p.fillRect( x, y, spacing, curApp->pixmap().height() + 1, colorGroup().highlight() );
184 else 206 else
185 // p.eraseRect( x, y, spacing, curApp->pixmap().height()+1 ); 207 // p.eraseRect( x, y, spacing, curApp->pixmap().height()+1 );
186 p.drawPixmap( x, y, curApp->pixmap() ); 208 p.drawPixmap( x, y, curApp->pixmap() );
187 x += spacing; 209 x += spacing;
188 } 210 }
189 } 211 }
190} 212}
191 213
192QSize RunningAppBar::sizeHint() const 214QSize RunningAppBar::sizeHint() const
193{ 215{
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)
201 QCopChannel* channel = new QCopChannel( "QPE/System", this ); 223{
202 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)), 224 QCopChannel* channel = new QCopChannel( "QPE/System", this );
203 this, SLOT(received(const QCString&, const QByteArray&)) ); 225 connect( channel, SIGNAL(received(const QCString&, const QByteArray&)),
204 connect(&m_Timer, SIGNAL(timeout()), this, SLOT(timerExpired())); 226 this, SLOT(received(const QCString&, const QByteArray&)) );
205 m_Timer.start(RAISE_TIMEOUT_MS, TRUE); 227 connect(&m_Timer, SIGNAL(timeout()), this, SLOT(timerExpired()));
228 m_Timer.start(RAISE_TIMEOUT_MS, TRUE);
206} 229}
207 230
208AppMonitor::~AppMonitor() { 231AppMonitor::~AppMonitor()
209 if (m_AppKillerBox) { 232{
210 delete m_AppKillerBox; 233 if (m_AppKillerBox) {
211 m_AppKillerBox = 0L; 234 delete m_AppKillerBox;
212 } 235 m_AppKillerBox = 0L;
236 }
213} 237}
214 238
215void AppMonitor::received(const QCString& msg, const QByteArray& data) { 239void AppMonitor::received(const QCString& msg, const QByteArray& data)
216 QDataStream stream( data, IO_ReadOnly ); 240{
217 241 QDataStream stream( data, IO_ReadOnly );
218 if (msg == "appRaised(QString)") {
219 QString appName;
220 stream >> appName;
221 if (appName == m_App.exec()) {
222 // qDebug("Got a heartbeat from %s", appName.latin1());
223 m_Timer.stop();
224 // Check to make sure we're not waiting on user input...
225 if (m_AppKillerBox) {
226 // If we are, we kill the dialog box, and the code waiting on the result
227 // will clean us up (basically the user said "no").
228 delete m_AppKillerBox;
229 m_AppKillerBox = 0L;
230 }
231 else {
232 // Ok, we're not waiting on user input, so clean us up now.
233 // WE DELETE OURSELVES HERE! Don't do anything else!!
234 delete this;
235 }
236 }
237 }
238}
239 242
240void AppMonitor::timerExpired() { 243 if (msg == "appRaised(QString)") {
241 // qDebug("Checking in on %s", m_App.name().latin1()); 244 QString appName;
242 // We store this incase the application responds while we're 245 stream >> appName;
243 // waiting for user input so we know not to delete ourselves. This 246 if (appName == m_App.exec()) {
244 // will be cleaned up in the destructor. 247 // qDebug("Got a heartbeat from %s", appName.latin1());
245 m_AppKillerBox = new QMessageBox(tr("Application Problem"), 248 m_Timer.stop();
246 tr("<p>%1 is not responding.</p>").arg(m_App.name()) + 249 // Check to make sure we're not waiting on user input...
247 tr("<p>Would you like to force the application to exit?</p>"), 250 if (m_AppKillerBox) {
248 QMessageBox::Warning, QMessageBox::Yes, 251 // If we are, we kill the dialog box, and the code waiting on the result
249 QMessageBox::No | QMessageBox::Default, 252 // will clean us up (basically the user said "no").
250 QMessageBox::NoButton); 253 delete m_AppKillerBox;
251 if (m_AppKillerBox->exec() == QMessageBox::Yes) { 254 m_AppKillerBox = 0L;
252 // qDebug("Killing the app!!! Bwuhahahaha!"); 255 }
253 m_PsProc = new QProcess(QString("ps")); 256 else {
254 m_PsProc->addArgument("h"); 257 // Ok, we're not waiting on user input, so clean us up now.
255 m_PsProc->addArgument("-C"); 258 // WE DELETE OURSELVES HERE! Don't do anything else!!
256 m_PsProc->addArgument(m_App.exec()); 259 delete this;
257 m_PsProc->addArgument("-o"); 260 }
258 m_PsProc->addArgument("pid"); 261 }
259 connect(m_PsProc, SIGNAL(processExited()), this, SLOT(psProcFinished())); 262 }
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} 263}
268 264
269void AppMonitor::psProcFinished() { 265void AppMonitor::timerExpired()
270 QString pid = m_PsProc->readLineStdout(); 266{
271 delete m_PsProc; 267 // We store this incase the application responds while we're
272 m_PsProc = 0L; 268 // waiting for user input so we know not to delete ourselves. This
273 269 // will be cleaned up in the destructor.
274 // qDebug("Killing app %s", pid.latin1()); 270 m_AppKillerBox = new QMessageBox(tr("Application Problem"),
275 if (pid.isEmpty()) { 271 tr("<p>%1 is not responding.</p>").arg(m_App.name()) +
276 // Hmm.. did the application bail before we got there? 272 tr("<p>Would you like to force the application to exit?</p>"),
277 qDebug("AppMonitor: Tried to kill application %s but ps couldn't find it.", m_App.exec().latin1()); 273 QMessageBox::Warning, QMessageBox::Yes,
278 } 274 QMessageBox::No | QMessageBox::Default,
279 else { 275 QMessageBox::NoButton);
280 int success = kill(pid.toUInt(), SIGKILL); 276 if ( m_AppKillerBox-> exec ( ) == QMessageBox::Yes ) {
281 if (success == 0) { 277 QDir proc ( "/proc/", "[0-9]*", QDir::Name | QDir::Reversed, QDir::Dirs );
282 m_Owner.removeTask(m_App); 278 QStringList allprocs = proc. entryList ( );
283 } 279
284 else { 280 pid_t mypid = ::getpid ( );
285 qWarning("Could not kill task %s", m_App.exec().latin1()); 281
286 } 282 for ( QStringList::Iterator it = allprocs. begin ( ); it != allprocs. end ( ); ++it ) {
287 } 283 if (( *it ). toInt ( ) <= mypid ) // only interested in children
288 284 continue;
289 // WE DELETE OURSELVES HERE! Don't do anything else!! 285
290 delete this; 286 QCString s = QString ( "/proc/" + *it + "/stat" ). local8Bit ( );
287
288 FILE *fp = ::fopen ( s. data ( ), "r" );
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 )
309 m_Owner. removeTask ( m_App );
310
311 ::free ( execptr );
312 break;
313 }
314 ::free ( execptr );
315 }
316 ::fclose ( fp );
317 }
318 }
319 }
320 delete this;
291} 321}
322