-rw-r--r-- | core/launcher/runningappbar.cpp | 441 | ||||
-rw-r--r-- | core/launcher/runningappbar.h | 78 |
2 files changed, 275 insertions, 244 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 | |||
@@ -1,291 +1,322 @@ | |||
1 | /********************************************************************** | 1 | /********************************************************************** |
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | 2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. |
3 | ** | 3 | ** |
4 | ** This file is part of the Qtopia Environment. | 4 | ** This file is part of the Qtopia Environment. |
5 | ** | 5 | ** |
6 | ** This file may be distributed and/or modified under the terms of the | 6 | ** This file may be distributed and/or modified under the terms of the |
7 | ** GNU General Public License version 2 as published by the Free Software | 7 | ** GNU General Public License version 2 as published by the Free Software |
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | 8 | ** Foundation and appearing in the file LICENSE.GPL included in the |
9 | ** packaging of this file. | 9 | ** packaging of this file. |
10 | ** | 10 | ** |
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | 11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
13 | ** | 13 | ** |
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | 14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. |
15 | ** | 15 | ** |
16 | ** Contact info@trolltech.com if any conditions of this licensing are | 16 | ** Contact info@trolltech.com if any conditions of this licensing are |
17 | ** not clear to you. | 17 | ** not clear to you. |
18 | ** | 18 | ** |
19 | ********************************************************************** | 19 | ********************************************************************** |
20 | */ | 20 | */ |
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" |
39 | 42 | ||
40 | RunningAppBar::RunningAppBar(QWidget* parent) | 43 | RunningAppBar::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 | ||
58 | RunningAppBar::~RunningAppBar() { | 60 | spacing = AppLnk::smallIconSize() + 3; |
59 | } | 61 | } |
60 | 62 | ||
61 | void RunningAppBar::newQcopChannel(const QString& channelName) { | 63 | RunningAppBar::~RunningAppBar() |
62 | QString prefix("QPE/Application/"); | 64 | {} |
63 | if (channelName.startsWith(prefix)) { | 65 | |
64 | QString appName = channelName.mid(prefix.length()); | 66 | void 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 | ||
73 | void RunningAppBar::removedQcopChannel(const QString& channelName) { | 79 | void 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 | ||
85 | void RunningAppBar::received(const QCString& msg, const QByteArray& data) { | 92 | void 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 | ||
100 | void RunningAppBar::addTask(const AppLnk& appLnk) { | 109 | void 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 | ||
108 | void RunningAppBar::removeTask(const AppLnk& appLnk) { | 118 | void 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 | ||
121 | void RunningAppBar::mousePressEvent(QMouseEvent *e) | 142 | void 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 | ||
145 | void RunningAppBar::mouseReleaseEvent(QMouseEvent *e) | 167 | void 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 | ||
167 | void RunningAppBar::paintEvent( QPaintEvent * ) | 189 | void 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 | ||
192 | QSize RunningAppBar::sizeHint() const | 214 | QSize 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 | ||
197 | const int AppMonitor::RAISE_TIMEOUT_MS = 500; | 219 | const int AppMonitor::RAISE_TIMEOUT_MS = 500; |
198 | 220 | ||
199 | AppMonitor::AppMonitor(const AppLnk& app, RunningAppBar& owner) | 221 | AppMonitor::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 | ||
208 | AppMonitor::~AppMonitor() { | 231 | AppMonitor::~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 | ||
215 | void AppMonitor::received(const QCString& msg, const QByteArray& data) { | 239 | void 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 | ||
240 | void 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 | ||
269 | void AppMonitor::psProcFinished() { | 265 | void 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 | |||
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 | |||
@@ -1,88 +1,88 @@ | |||
1 | /********************************************************************** | 1 | /********************************************************************** |
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | 2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. |
3 | ** | 3 | ** |
4 | ** This file is part of the Qtopia Environment. | 4 | ** This file is part of the Qtopia Environment. |
5 | ** | 5 | ** |
6 | ** This file may be distributed and/or modified under the terms of the | 6 | ** This file may be distributed and/or modified under the terms of the |
7 | ** GNU General Public License version 2 as published by the Free Software | 7 | ** GNU General Public License version 2 as published by the Free Software |
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | 8 | ** Foundation and appearing in the file LICENSE.GPL included in the |
9 | ** packaging of this file. | 9 | ** packaging of this file. |
10 | ** | 10 | ** |
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | 11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | 12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
13 | ** | 13 | ** |
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | 14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. |
15 | ** | 15 | ** |
16 | ** Contact info@trolltech.com if any conditions of this licensing are | 16 | ** Contact info@trolltech.com if any conditions of this licensing are |
17 | ** not clear to you. | 17 | ** not clear to you. |
18 | ** | 18 | ** |
19 | **********************************************************************/ | 19 | **********************************************************************/ |
20 | 20 | ||
21 | #ifndef RUNNING_APP_BAR_H | 21 | #ifndef RUNNING_APP_BAR_H |
22 | #define RUNNING_APP_BAR_H | 22 | #define RUNNING_APP_BAR_H |
23 | 23 | ||
24 | #include <qframe.h> | 24 | #include <qframe.h> |
25 | #include <qlist.h> | 25 | #include <qlist.h> |
26 | #include <qtimer.h> | 26 | #include <qtimer.h> |
27 | 27 | ||
28 | class AppLnk; | 28 | class AppLnk; |
29 | class AppLnkSet; | 29 | class AppLnkSet; |
30 | class QCString; | 30 | class QCString; |
31 | class QProcess; | 31 | class QProcess; |
32 | class QMessageBox; | 32 | class QMessageBox; |
33 | 33 | ||
34 | class RunningAppBar : public QFrame { | 34 | class RunningAppBar : public QFrame |
35 | Q_OBJECT | 35 | { |
36 | Q_OBJECT | ||
36 | 37 | ||
37 | public: | 38 | public: |
38 | RunningAppBar(QWidget* parent); | 39 | RunningAppBar(QWidget* parent); |
39 | ~RunningAppBar(); | 40 | ~RunningAppBar(); |
40 | |||
41 | void addTask(const AppLnk& appLnk); | ||
42 | void removeTask(const AppLnk& appLnk); | ||
43 | void paintEvent(QPaintEvent* event); | ||
44 | void mousePressEvent(QMouseEvent*); | ||
45 | void mouseReleaseEvent(QMouseEvent*); | ||
46 | QSize sizeHint() const; | ||
47 | 41 | ||
48 | private slots: | 42 | void addTask(const AppLnk& appLnk); |
49 | void newQcopChannel(const QString& channel); | 43 | void removeTask(const AppLnk& appLnk); |
50 | void removedQcopChannel(const QString& channel); | 44 | void paintEvent(QPaintEvent* event); |
51 | void received(const QCString& msg, const QByteArray& data); | 45 | void mousePressEvent(QMouseEvent*); |
46 | void mouseReleaseEvent(QMouseEvent*); | ||
47 | QSize sizeHint() const; | ||
52 | 48 | ||
53 | private: | 49 | private slots: |
54 | AppLnkSet* m_AppLnkSet; | 50 | void newQcopChannel(const QString& channel); |
55 | QList<AppLnk> m_AppList; | 51 | void removedQcopChannel(const QString& channel); |
56 | int m_SelectedAppIndex; | 52 | void received(const QCString& msg, const QByteArray& data); |
57 | int spacing; | 53 | |
54 | private: | ||
55 | AppLnkSet* m_AppLnkSet; | ||
56 | QList<AppLnk> m_AppList; | ||
57 | int m_SelectedAppIndex; | ||
58 | int spacing; | ||
58 | }; | 59 | }; |
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 | */ |
65 | class AppMonitor : public QObject { | 66 | class AppMonitor : public QObject |
66 | Q_OBJECT | 67 | { |
67 | 68 | Q_OBJECT | |
68 | public: | 69 | |
69 | static const int RAISE_TIMEOUT_MS; | 70 | public: |
71 | static const int RAISE_TIMEOUT_MS; | ||
72 | |||
73 | AppMonitor(const AppLnk& app, RunningAppBar& owner); | ||
74 | ~AppMonitor(); | ||
70 | 75 | ||
71 | AppMonitor(const AppLnk& app, RunningAppBar& owner); | 76 | private slots: |
72 | ~AppMonitor(); | 77 | void timerExpired(); |
73 | 78 | void received(const QCString& msg, const QByteArray& data); | |
74 | private slots: | ||
75 | void timerExpired(); | ||
76 | 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 | ||