Diffstat (limited to 'core/launcher/runningappbar.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/launcher/runningappbar.cpp | 356 |
1 files changed, 111 insertions, 245 deletions
diff --git a/core/launcher/runningappbar.cpp b/core/launcher/runningappbar.cpp index 356200b..1fda5a4 100644 --- a/core/launcher/runningappbar.cpp +++ b/core/launcher/runningappbar.cpp | |||
@@ -16,298 +16,164 @@ | |||
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 | */ | ||
21 | 20 | ||
22 | #define QTOPIA_INTERNAL_PRELOADACCESS | 21 | #define QTOPIA_INTERNAL_PRELOADACCESS |
23 | 22 | ||
24 | // For "kill" | 23 | #include <qtopia/global.h> |
25 | #include <sys/types.h> | 24 | |
26 | #include <signal.h> | ||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | 25 | #include <stdlib.h> |
29 | 26 | ||
30 | #include <qdir.h> | ||
31 | #include <qtimer.h> | 27 | #include <qtimer.h> |
32 | #include <qpopupmenu.h> | 28 | #include <qpopupmenu.h> |
33 | #include <qmessagebox.h> | ||
34 | #include <qpainter.h> | 29 | #include <qpainter.h> |
35 | #include <opie/oprocess.h> | 30 | #include <qmessagebox.h> |
36 | #include <qpe/qpeapplication.h> | 31 | |
37 | #include <qpe/applnk.h> | 32 | #include <qtopia/qpeapplication.h> |
38 | #include <qpe/qcopenvelope_qws.h> | 33 | #include <qtopia/applnk.h> |
39 | #include <qpe/global.h> | 34 | #include <qtopia/qcopenvelope_qws.h> |
40 | #include <qwindowsystem_qws.h> | 35 | #include <qtopia/mimetype.h> |
36 | |||
41 | #include "runningappbar.h" | 37 | #include "runningappbar.h" |
38 | #include "serverinterface.h" | ||
42 | 39 | ||
43 | RunningAppBar::RunningAppBar(QWidget* parent) | 40 | RunningAppBar::RunningAppBar(QWidget* parent) |
44 | : QFrame(parent), m_AppLnkSet(0L), m_SelectedAppIndex( -1) | 41 | : QFrame(parent), selectedAppIndex(-1) |
45 | { | 42 | { |
46 | setBackgroundMode( PaletteBackground ); | 43 | QCopChannel* channel = new QCopChannel( "QPE/System", this ); |
47 | 44 | connect( channel, SIGNAL(received(const QCString&, const QByteArray&)), | |
48 | m_AppLnkSet = new AppLnkSet( QPEApplication::qpeDir() + "apps" ); | 45 | this, SLOT(received(const QCString&, const QByteArray&)) ); |
49 | |||
50 | #ifdef QWS | ||
51 | 46 | ||
52 | connect(qwsServer, SIGNAL(newChannel(const QString&)), this, SLOT(newQcopChannel(const QString&))); | 47 | spacing = AppLnk::smallIconSize()+3; |
53 | connect(qwsServer, SIGNAL(removedChannel(const QString&)), this, SLOT(removedQcopChannel(const QString&))); | ||
54 | #endif | ||
55 | |||
56 | QCopChannel* channel = new QCopChannel( "QPE/System", this ); | ||
57 | connect( channel, SIGNAL(received(const QCString&, const QByteArray&)), | ||
58 | this, SLOT(received(const QCString&, const QByteArray&)) ); | ||
59 | |||
60 | spacing = AppLnk::smallIconSize() + 3; | ||
61 | } | 48 | } |
62 | 49 | ||
63 | RunningAppBar::~RunningAppBar() | 50 | RunningAppBar::~RunningAppBar() |
64 | {} | ||
65 | |||
66 | void RunningAppBar::newQcopChannel(const QString& channelName) | ||
67 | { | ||
68 | QString prefix("QPE/Application/"); | ||
69 | if (channelName.startsWith(prefix)) { | ||
70 | QString appName = channelName.mid(prefix.length()); | ||
71 | // qDebug("App %s just connected!", appName.latin1()); | ||
72 | const AppLnk* newGuy = m_AppLnkSet->findExec(appName); | ||
73 | if (newGuy && !newGuy->isPreloaded()) { | ||
74 | addTask(*newGuy); | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | void RunningAppBar::removedQcopChannel(const QString& channelName) | ||
80 | { | 51 | { |
81 | QString prefix("QPE/Application/"); | ||
82 | if (channelName.startsWith(prefix)) { | ||
83 | QString appName = channelName.mid(prefix.length()); | ||
84 | qDebug("App %s just disconnected!", appName.latin1()); | ||
85 | const AppLnk* newGuy = m_AppLnkSet->findExec(appName); | ||
86 | if (newGuy) { | ||
87 | removeTask(*newGuy); | ||
88 | } | ||
89 | } | ||
90 | } | 52 | } |
91 | 53 | ||
92 | void RunningAppBar::received(const QCString& msg, const QByteArray& data) | 54 | void RunningAppBar::received(const QCString& msg, const QByteArray& data) { |
93 | { | 55 | // Since fast apps appear and disappear without disconnecting from their |
94 | // Since fast apps appear and disappear without disconnecting from their | 56 | // 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. | 57 | QDataStream stream( data, IO_ReadOnly ); |
96 | QDataStream stream( data, IO_ReadOnly ); | 58 | if ( msg == "fastAppShowing(QString)") { |
97 | if ( msg == "fastAppShowing(QString)") { | 59 | QString appName; |
98 | QString appName; | 60 | stream >> appName; |
99 | stream >> appName; | 61 | // qDebug("fastAppShowing %s", appName.data() ); |
100 | addTask(*m_AppLnkSet->findExec(appName)); | 62 | const AppLnk* f = ServerInterface::appLnks().findExec(appName); |
101 | } | 63 | if ( f ) addTask(*f); |
102 | else if ( msg == "fastAppHiding(QString)") { | 64 | } else if ( msg == "fastAppHiding(QString)") { |
103 | QString appName; | 65 | QString appName; |
104 | stream >> appName; | 66 | stream >> appName; |
105 | removeTask(*m_AppLnkSet->findExec(appName)); | 67 | const AppLnk* f = ServerInterface::appLnks().findExec(appName); |
106 | } | 68 | if ( f ) removeTask(*f); |
69 | } | ||
107 | } | 70 | } |
108 | 71 | ||
109 | void RunningAppBar::addTask(const AppLnk& appLnk) | 72 | void RunningAppBar::addTask(const AppLnk& appLnk) { |
110 | { | 73 | qDebug("Added %s to app list.", appLnk.name().latin1()); |
111 | // qDebug("Added %s to app list.", appLnk.name().latin1()); | 74 | AppLnk* newApp = new AppLnk(appLnk); |
112 | AppLnk* newApp = new AppLnk(appLnk); | 75 | newApp->setExec(appLnk.exec()); |
113 | newApp->setExec(appLnk.exec()); | 76 | appList.prepend(newApp); |
114 | m_AppList.prepend(newApp); | 77 | update(); |
115 | update(); | ||
116 | } | 78 | } |
117 | 79 | ||
118 | void RunningAppBar::removeTask(const AppLnk& appLnk) | 80 | void RunningAppBar::removeTask(const AppLnk& appLnk) { |
119 | { | 81 | unsigned int i = 0; |
120 | unsigned int i = 0; | 82 | for (; i < appList.count() ; i++) { |
121 | for (; i < m_AppList.count() ; i++) { | 83 | AppLnk* target = appList.at(i); |
122 | AppLnk* target = m_AppList.at(i); | 84 | if (target->exec() == appLnk.exec()) { |
123 | if (target->exec() == appLnk.exec()) { | 85 | qDebug("Removing %s from app list.", appLnk.name().latin1()); |
124 | qDebug("Removing %s from app list.", appLnk.name().latin1()); | 86 | appList.remove(); |
125 | m_AppList.remove(); | 87 | delete target; |
126 | 88 | } | |
127 | delete target; | 89 | } |
128 | } | 90 | update(); |
129 | } | ||
130 | update(); | ||
131 | } | 91 | } |
132 | 92 | ||
133 | void RunningAppBar::mousePressEvent(QMouseEvent *e) | 93 | void RunningAppBar::mousePressEvent(QMouseEvent *e) |
134 | { | 94 | { |
135 | // Find out if the user is clicking on an app icon... | 95 | // Find out if the user is clicking on an app icon... |
136 | // If so, snag the index so when we repaint we show it | 96 | // If so, snag the index so when we repaint we show it |
137 | // as highlighed. | 97 | // as highlighed. |
138 | m_SelectedAppIndex = 0; | 98 | selectedAppIndex = 0; |
139 | int x = 0; | 99 | int x=0; |
140 | QListIterator<AppLnk> it( m_AppList ); | 100 | QListIterator<AppLnk> it( appList ); |
141 | for ( ; it.current(); ++it, ++m_SelectedAppIndex, x += spacing ) { | 101 | for ( ; it.current(); ++it,++selectedAppIndex,x+=spacing ) { |
142 | if ( x + spacing <= width() ) { | 102 | if ( x + spacing <= width() ) { |
143 | if ( e->x() >= x && e->x() < x + spacing ) { | 103 | if ( e->x() >= x && e->x() < x+spacing ) { |
144 | if ( m_SelectedAppIndex < (int)m_AppList.count() ) { | 104 | if ( selectedAppIndex < (int)appList.count() ) { |
145 | repaint(FALSE); | 105 | repaint(FALSE); |
146 | return ; | 106 | return; |
147 | } | ||
148 | } | ||
149 | } | ||
150 | else { | ||
151 | break; | ||
152 | } | ||
153 | } | 107 | } |
154 | m_SelectedAppIndex = -1; | 108 | } |
155 | repaint( FALSE ); | 109 | } else { |
110 | break; | ||
111 | } | ||
112 | } | ||
113 | selectedAppIndex = -1; | ||
114 | repaint( FALSE ); | ||
156 | } | 115 | } |
157 | 116 | ||
158 | void RunningAppBar::mouseReleaseEvent(QMouseEvent *e) | 117 | void RunningAppBar::mouseReleaseEvent(QMouseEvent *e) |
159 | { | 118 | { |
160 | if (e->button() == QMouseEvent::RightButton) { | 119 | if (e->button() == QMouseEvent::RightButton) |
161 | return ; | 120 | return; |
162 | } | 121 | if ( selectedAppIndex >= 0 ) { |
163 | if ( m_SelectedAppIndex >= 0 ) { | 122 | QString app = appList.at(selectedAppIndex)->exec(); |
164 | QString channel = QString("QPE/Application/") + m_AppList.at(m_SelectedAppIndex)->exec(); | 123 | QCopEnvelope e("QPE/System", "raise(QString)"); |
165 | if (QCopChannel::isRegistered(channel.latin1())) { | 124 | e << app; |
166 | // qDebug("%s is running!", m_AppList.at(m_SelectedAppIndex)->exec().latin1()); | 125 | selectedAppIndex = -1; |
167 | QCopEnvelope e(channel.latin1(), "raise()"); | 126 | update(); |
168 | // This class will delete itself after hearing from the app or the timer expiring | 127 | } |
169 | (void)new AppMonitor(*m_AppList.at(m_SelectedAppIndex), *this); | ||
170 | } | ||
171 | else { | ||
172 | removeTask(*m_AppList.at(m_SelectedAppIndex)); | ||
173 | } | ||
174 | |||
175 | m_SelectedAppIndex = -1; | ||
176 | update(); | ||
177 | } | ||
178 | } | 128 | } |
179 | 129 | ||
180 | void RunningAppBar::paintEvent( QPaintEvent * ) | 130 | void RunningAppBar::paintEvent( QPaintEvent * ) |
181 | { | 131 | { |
182 | QPainter p( this ); | 132 | QPainter p( this ); |
183 | AppLnk *curApp; | 133 | AppLnk *curApp; |
184 | int x = 0; | 134 | int x = 0; |
185 | int y = (height() - AppLnk::smallIconSize()) / 2; | 135 | int y = (height() - AppLnk::smallIconSize()) / 2; |
186 | int i = 0; | 136 | int i = 0; |
187 | 137 | ||
188 | //p.fillRect( 0, 0, width(), height(), colorGroup().background() ); | 138 | p.fillRect( 0, 0, width(), height(), colorGroup().background() ); |
189 | 139 | ||
190 | QListIterator<AppLnk> it(m_AppList); | 140 | QListIterator<AppLnk> it(appList); |
191 | 141 | ||
192 | for (; it.current(); i++, ++it ) { | 142 | for (; it.current(); i++, ++it ) { |
193 | if ( x + spacing <= width() ) { | 143 | if ( x + spacing <= width() ) { |
194 | curApp = it.current(); | 144 | curApp = it.current(); |
195 | if ( (int)i == m_SelectedAppIndex ) | 145 | qWarning("Drawing %s", curApp->name().latin1() ); |
196 | p.fillRect( x, y, spacing, curApp->pixmap().height() + 1, colorGroup().highlight() ); | 146 | if ( (int)i == selectedAppIndex ) |
197 | else | 147 | p.fillRect( x, y, spacing, curApp->pixmap().height()+1, colorGroup().highlight() ); |
198 | // p.eraseRect( x, y, spacing, curApp->pixmap().height()+1 ); | 148 | else |
199 | p.drawPixmap( x, y, curApp->pixmap() ); | 149 | p.eraseRect( x, y, spacing, curApp->pixmap().height()+1 ); |
200 | x += spacing; | 150 | p.drawPixmap( x, y, curApp->pixmap() ); |
201 | } | 151 | x += spacing; |
202 | } | 152 | } |
153 | } | ||
203 | } | 154 | } |
204 | 155 | ||
205 | QSize RunningAppBar::sizeHint() const | 156 | QSize RunningAppBar::sizeHint() const |
206 | { | 157 | { |
207 | return QSize( frameWidth(), AppLnk::smallIconSize() + frameWidth()*2 + 3 ); | 158 | return QSize( frameWidth(), AppLnk::smallIconSize()+frameWidth()*2+3 ); |
208 | } | 159 | } |
209 | 160 | ||
210 | const int AppMonitor::RAISE_TIMEOUT_MS = 500; | 161 | void RunningAppBar::applicationLaunched(const QString &appName) |
211 | |||
212 | AppMonitor::AppMonitor(const AppLnk& app, RunningAppBar& owner) | ||
213 | : QObject(0L), m_Owner(owner), m_App(app), m_AppKillerBox(0L) | ||
214 | { | 162 | { |
215 | QCopChannel* channel = new QCopChannel( "QPE/System", this ); | 163 | qDebug("desktop:: app: %s launched with pid ", appName.data() ); |
216 | connect( channel, SIGNAL(received(const QCString&, const QByteArray&)), | 164 | const AppLnk* newGuy = ServerInterface::appLnks().findExec(appName); |
217 | this, SLOT(received(const QCString&, const QByteArray&)) ); | 165 | if ( newGuy && !newGuy->isPreloaded() ) { |
218 | connect(&m_Timer, SIGNAL(timeout()), this, SLOT(timerExpired())); | 166 | addTask( *newGuy ); |
219 | m_Timer.start(RAISE_TIMEOUT_MS, TRUE); | 167 | } |
220 | } | 168 | } |
221 | 169 | ||
222 | AppMonitor::~AppMonitor() | 170 | void RunningAppBar::applicationTerminated(const QString &app) |
223 | { | 171 | { |
224 | if (m_AppKillerBox) { | 172 | const AppLnk* gone = ServerInterface::appLnks().findExec(app); |
225 | delete m_AppKillerBox; | 173 | if ( gone ) { |
226 | m_AppKillerBox = 0L; | 174 | removeTask(*gone); |
227 | } | 175 | } |
228 | } | ||
229 | |||
230 | void AppMonitor::received(const QCString& msg, const QByteArray& data) | ||
231 | { | ||
232 | QDataStream stream( data, IO_ReadOnly ); | ||
233 | |||
234 | if (msg == "appRaised(QString)") { | ||
235 | QString appName; | ||
236 | stream >> appName; | ||
237 | if (appName == m_App.exec()) { | ||
238 | // qDebug("Got a heartbeat from %s", appName.latin1()); | ||
239 | m_Timer.stop(); | ||
240 | // Check to make sure we're not waiting on user input... | ||
241 | if (m_AppKillerBox) { | ||
242 | // If we are, we kill the dialog box, and the code waiting on the result | ||
243 | // will clean us up (basically the user said "no"). | ||
244 | delete m_AppKillerBox; | ||
245 | m_AppKillerBox = 0L; | ||
246 | } | ||
247 | else { | ||
248 | // Ok, we're not waiting on user input, so clean us up now. | ||
249 | // WE DELETE OURSELVES HERE! Don't do anything else!! | ||
250 | delete this; | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | } | 176 | } |
255 | 177 | ||
256 | void AppMonitor::timerExpired() | ||
257 | { | ||
258 | // We store this incase the application responds while we're | ||
259 | // waiting for user input so we know not to delete ourselves. This | ||
260 | // will be cleaned up in the destructor. | ||
261 | m_AppKillerBox = new QMessageBox(tr("Application Problem"), | ||
262 | tr("<p>%1 is not responding.</p>").arg(m_App.name()) + | ||
263 | tr("<p>Would you like to force the application to exit?</p>"), | ||
264 | QMessageBox::Warning, QMessageBox::Yes, | ||
265 | QMessageBox::No | QMessageBox::Default, | ||
266 | QMessageBox::NoButton); | ||
267 | if ( m_AppKillerBox-> exec ( ) == QMessageBox::Yes ) { | ||
268 | QDir proc ( "/proc/", "[0-9]*", QDir::Name | QDir::Reversed, QDir::Dirs ); | ||
269 | QStringList allprocs = proc. entryList ( ); | ||
270 | |||
271 | pid_t mypid = ::getpid ( ); | ||
272 | |||
273 | for ( QStringList::Iterator it = allprocs. begin ( ); it != allprocs. end ( ); ++it ) { | ||
274 | if (( *it ). toInt ( ) <= mypid ) // only interested in children | ||
275 | continue; | ||
276 | |||
277 | QCString s = QString ( "/proc/" + *it + "/stat" ). local8Bit ( ); | ||
278 | |||
279 | FILE *fp = ::fopen ( s. data ( ), "r" ); | ||
280 | if ( fp ) { | ||
281 | pid_t pid, ppid; | ||
282 | char *execptr, *exec = 0; | ||
283 | |||
284 | if ( ::fscanf ( fp, "%d %as %*c %d ", &pid, &execptr, &ppid ) == 3 ) { | ||
285 | exec = execptr [0] ? execptr + 1 : execptr; | ||
286 | if ( exec [0] ) | ||
287 | exec [::strlen ( exec ) - 1] = 0; | ||
288 | |||
289 | if (( ppid == ::getpid ( )) && ( m_App. exec ( ). local8Bit ( ) == exec )) { | ||
290 | bool success = false; | ||
291 | 178 | ||
292 | qDebug ( "trying to kill pid=%d, exec=%s, ppid=%d", pid, exec, ppid ); | ||
293 | |||
294 | |||
295 | success |= ( ::kill ( pid, SIGTERM ) == 0 ); | ||
296 | ::usleep ( 1000 * 500 ); | ||
297 | success |= ( ::kill ( pid, SIGKILL ) == 0 ); | ||
298 | |||
299 | if ( success ) | ||
300 | m_Owner. removeTask ( m_App ); | ||
301 | |||
302 | ::free ( execptr ); | ||
303 | break; | ||
304 | } | ||
305 | ::free ( execptr ); | ||
306 | } | ||
307 | ::fclose ( fp ); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | delete this; | ||
312 | } | ||
313 | 179 | ||