summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/multimedia/opieplayer2/skin.cpp1
-rw-r--r--noncore/multimedia/opieplayer2/threadutil.cpp1
2 files changed, 2 insertions, 0 deletions
diff --git a/noncore/multimedia/opieplayer2/skin.cpp b/noncore/multimedia/opieplayer2/skin.cpp
index 84f5f87..5d8929e 100644
--- a/noncore/multimedia/opieplayer2/skin.cpp
+++ b/noncore/multimedia/opieplayer2/skin.cpp
@@ -1,322 +1,323 @@
1/* 1/*
2 Copyright (C) 2002 Simon Hausmann <simon@lst.de> 2 Copyright (C) 2002 Simon Hausmann <simon@lst.de>
3 (C) 2002 Max Reiss <harlekin@handhelds.org> 3 (C) 2002 Max Reiss <harlekin@handhelds.org>
4 (C) 2002 L. Potter <ljp@llornkcor.com> 4 (C) 2002 L. Potter <ljp@llornkcor.com>
5 (C) 2002 Holger Freyther <zecke@handhelds.org> 5 (C) 2002 Holger Freyther <zecke@handhelds.org>
6 6
7 This program is free software; you can redistribute it and/or 7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public 8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either 9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version. 10 version 2 of the License, or (at your option) any later version.
11 11
12 This program is distributed in the hope that it will be useful, 12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details. 15 General Public License for more details.
16 16
17 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING. If not, write to 18 along with this program; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. 20 Boston, MA 02111-1307, USA.
21*/ 21*/
22 22
23#include "skin.h" 23#include "skin.h"
24#include "singleton.h" 24#include "singleton.h"
25#include <opie2/odebug.h>
25 26
26#include <qcache.h> 27#include <qcache.h>
27#include <qtimer.h> 28#include <qtimer.h>
28 29
29#include <qpe/config.h> 30#include <qpe/config.h>
30 31
31#include <assert.h> 32#include <assert.h>
32 33
33struct SkinData 34struct SkinData
34{ 35{
35 typedef QMap<QString, QImage> ButtonMaskImageMap; 36 typedef QMap<QString, QImage> ButtonMaskImageMap;
36 37
37 QPixmap backgroundPixmap; 38 QPixmap backgroundPixmap;
38 QImage buttonUpImage; 39 QImage buttonUpImage;
39 QImage buttonDownImage; 40 QImage buttonDownImage;
40 QImage buttonMask; 41 QImage buttonMask;
41 ButtonMaskImageMap buttonMasks; 42 ButtonMaskImageMap buttonMasks;
42}; 43};
43 44
44class SkinCache : public Singleton<SkinCache> 45class SkinCache : public Singleton<SkinCache>
45{ 46{
46public: 47public:
47 SkinCache(); 48 SkinCache();
48 49
49 SkinData *lookupAndTake( const QString &skinPath, const QString &fileNameInfix ); 50 SkinData *lookupAndTake( const QString &skinPath, const QString &fileNameInfix );
50 51
51 void store( const QString &skinPath, const QString &fileNameInfix, SkinData *data ); 52 void store( const QString &skinPath, const QString &fileNameInfix, SkinData *data );
52 53
53private: 54private:
54 typedef QCache<SkinData> DataCache; 55 typedef QCache<SkinData> DataCache;
55 typedef QCache<QPixmap> BackgroundPixmapCache; 56 typedef QCache<QPixmap> BackgroundPixmapCache;
56 57
57 template <class CacheType> 58 template <class CacheType>
58 void store( const QCache<CacheType> &cache, const QString &key, CacheType *data ); 59 void store( const QCache<CacheType> &cache, const QString &key, CacheType *data );
59 60
60 DataCache m_cache; 61 DataCache m_cache;
61 BackgroundPixmapCache m_backgroundPixmapCache; 62 BackgroundPixmapCache m_backgroundPixmapCache;
62}; 63};
63 64
64Skin::Skin( const QString &name, const QString &fileNameInfix ) 65Skin::Skin( const QString &name, const QString &fileNameInfix )
65 : m_fileNameInfix( fileNameInfix ) 66 : m_fileNameInfix( fileNameInfix )
66{ 67{
67 init( name ); 68 init( name );
68} 69}
69 70
70Skin::Skin( const QString &fileNameInfix ) 71Skin::Skin( const QString &fileNameInfix )
71 : m_fileNameInfix( fileNameInfix ) 72 : m_fileNameInfix( fileNameInfix )
72{ 73{
73 init( defaultSkinName() ); 74 init( defaultSkinName() );
74} 75}
75 76
76Skin::~Skin() 77Skin::~Skin()
77{ 78{
78 if ( m_isCachable ) 79 if ( m_isCachable )
79 SkinCache::self().store( m_skinPath, m_fileNameInfix, d ); 80 SkinCache::self().store( m_skinPath, m_fileNameInfix, d );
80 else 81 else
81 delete d; 82 delete d;
82} 83}
83 84
84void Skin::init( const QString &name ) 85void Skin::init( const QString &name )
85{ 86{
86 m_isCachable = true; 87 m_isCachable = true;
87 m_skinPath = "opieplayer2/skins/" + name; 88 m_skinPath = "opieplayer2/skins/" + name;
88 d = SkinCache::self().lookupAndTake( m_skinPath, m_fileNameInfix ); 89 d = SkinCache::self().lookupAndTake( m_skinPath, m_fileNameInfix );
89} 90}
90 91
91QPixmap Skin::backgroundPixmap() const 92QPixmap Skin::backgroundPixmap() const
92{ 93{
93 if ( d->backgroundPixmap.isNull() ) 94 if ( d->backgroundPixmap.isNull() )
94 d->backgroundPixmap = loadImage( QString( "%1/background" ).arg( m_skinPath ) ); 95 d->backgroundPixmap = loadImage( QString( "%1/background" ).arg( m_skinPath ) );
95 return d->backgroundPixmap; 96 return d->backgroundPixmap;
96} 97}
97 98
98QImage Skin::buttonUpImage() const 99QImage Skin::buttonUpImage() const
99{ 100{
100 if ( d->buttonUpImage.isNull() ) 101 if ( d->buttonUpImage.isNull() )
101 d->buttonUpImage = loadImage( QString( "%1/skin%2_up" ).arg( m_skinPath ).arg( m_fileNameInfix ) ); 102 d->buttonUpImage = loadImage( QString( "%1/skin%2_up" ).arg( m_skinPath ).arg( m_fileNameInfix ) );
102 return d->buttonUpImage; 103 return d->buttonUpImage;
103} 104}
104 105
105QImage Skin::buttonDownImage() const 106QImage Skin::buttonDownImage() const
106{ 107{
107 if ( d->buttonDownImage.isNull() ) 108 if ( d->buttonDownImage.isNull() )
108 d->buttonDownImage = loadImage( QString( "%1/skin%2_down" ).arg( m_skinPath ).arg( m_fileNameInfix ) ); 109 d->buttonDownImage = loadImage( QString( "%1/skin%2_down" ).arg( m_skinPath ).arg( m_fileNameInfix ) );
109 return d->buttonDownImage; 110 return d->buttonDownImage;
110} 111}
111 112
112QImage Skin::buttonMask( const MediaWidget::SkinButtonInfo *skinButtonInfo, uint buttonCount ) const 113QImage Skin::buttonMask( const MediaWidget::SkinButtonInfo *skinButtonInfo, uint buttonCount ) const
113{ 114{
114 if ( !d->buttonMask.isNull() ) 115 if ( !d->buttonMask.isNull() )
115 return d->buttonMask; 116 return d->buttonMask;
116 117
117 QSize buttonAreaSize = buttonUpImage().size(); 118 QSize buttonAreaSize = buttonUpImage().size();
118 119
119 d->buttonMask = QImage( buttonAreaSize, 8, 255 ); 120 d->buttonMask = QImage( buttonAreaSize, 8, 255 );
120 d->buttonMask.fill( 0 ); 121 d->buttonMask.fill( 0 );
121 122
122 for ( uint i = 0; i < buttonCount; ++i ) 123 for ( uint i = 0; i < buttonCount; ++i )
123 addButtonToMask( skinButtonInfo[ i ].command + 1, buttonMaskImage( skinButtonInfo[ i ].fileName ) ); 124 addButtonToMask( skinButtonInfo[ i ].command + 1, buttonMaskImage( skinButtonInfo[ i ].fileName ) );
124 125
125 return d->buttonMask; 126 return d->buttonMask;
126} 127}
127 128
128void Skin::addButtonToMask( int tag, const QImage &maskImage ) const 129void Skin::addButtonToMask( int tag, const QImage &maskImage ) const
129{ 130{
130 if ( maskImage.isNull() ) 131 if ( maskImage.isNull() )
131 return; 132 return;
132 133
133 uchar **dest = d->buttonMask.jumpTable(); 134 uchar **dest = d->buttonMask.jumpTable();
134 for ( int y = 0; y < d->buttonMask.height(); y++ ) { 135 for ( int y = 0; y < d->buttonMask.height(); y++ ) {
135 uchar *line = dest[y]; 136 uchar *line = dest[y];
136 for ( int x = 0; x < d->buttonMask.width(); x++ ) 137 for ( int x = 0; x < d->buttonMask.width(); x++ )
137 if ( !qRed( maskImage.pixel( x, y ) ) ) 138 if ( !qRed( maskImage.pixel( x, y ) ) )
138 line[x] = tag; 139 line[x] = tag;
139 } 140 }
140} 141}
141 142
142QImage Skin::buttonMaskImage( const QString &fileName ) const 143QImage Skin::buttonMaskImage( const QString &fileName ) const
143{ 144{
144 SkinData::ButtonMaskImageMap::Iterator it = d->buttonMasks.find( fileName ); 145 SkinData::ButtonMaskImageMap::Iterator it = d->buttonMasks.find( fileName );
145 if ( it == d->buttonMasks.end() ) { 146 if ( it == d->buttonMasks.end() ) {
146 QString prefix = m_skinPath + QString::fromLatin1( "/skin%1_mask_" ).arg( m_fileNameInfix ); 147 QString prefix = m_skinPath + QString::fromLatin1( "/skin%1_mask_" ).arg( m_fileNameInfix );
147 QString path = prefix + fileName; 148 QString path = prefix + fileName;
148 it = d->buttonMasks.insert( fileName, loadImage( path ) ); 149 it = d->buttonMasks.insert( fileName, loadImage( path ) );
149 } 150 }
150 return *it; 151 return *it;
151} 152}
152 153
153QString Skin::defaultSkinName() 154QString Skin::defaultSkinName()
154{ 155{
155 Config cfg( "OpiePlayer" ); 156 Config cfg( "OpiePlayer" );
156 cfg.setGroup( "Options" ); 157 cfg.setGroup( "Options" );
157 return cfg.readEntry( "Skin", "default" ); 158 return cfg.readEntry( "Skin", "default" );
158} 159}
159 160
160QImage Skin::loadImage( const QString &fileName ) 161QImage Skin::loadImage( const QString &fileName )
161{ 162{
162 return QImage( Resource::findPixmap( fileName ) ); 163 return QImage( Resource::findPixmap( fileName ) );
163} 164}
164 165
165SkinCache::SkinCache() 166SkinCache::SkinCache()
166{ 167{
167 // let's say we cache two skins (audio+video) at maximum 168 // let's say we cache two skins (audio+video) at maximum
168 m_cache.setMaxCost( 2 ); 169 m_cache.setMaxCost( 2 );
169 // ... and one background pixmap 170 // ... and one background pixmap
170 m_backgroundPixmapCache.setMaxCost( 1 ); 171 m_backgroundPixmapCache.setMaxCost( 1 );
171} 172}
172 173
173SkinData *SkinCache::lookupAndTake( const QString &skinPath, const QString &fileNameInfix ) 174SkinData *SkinCache::lookupAndTake( const QString &skinPath, const QString &fileNameInfix )
174{ 175{
175 QString key = skinPath + fileNameInfix; 176 QString key = skinPath + fileNameInfix;
176 177
177 SkinData *data = m_cache.take( key ); 178 SkinData *data = m_cache.take( key );
178 if ( !data ) 179 if ( !data )
179 data = new SkinData; 180 data = new SkinData;
180 else 181 else
181 odebug << "SkinCache: hit" << oendl; 182 odebug << "SkinCache: hit" << oendl;
182 183
183 QPixmap *bgPixmap = m_backgroundPixmapCache.find( skinPath ); 184 QPixmap *bgPixmap = m_backgroundPixmapCache.find( skinPath );
184 if ( bgPixmap ) { 185 if ( bgPixmap ) {
185 odebug << "SkinCache: hit on bgpixmap" << oendl; 186 odebug << "SkinCache: hit on bgpixmap" << oendl;
186 data->backgroundPixmap = *bgPixmap; 187 data->backgroundPixmap = *bgPixmap;
187 } 188 }
188 else 189 else
189 data->backgroundPixmap = QPixmap(); 190 data->backgroundPixmap = QPixmap();
190 191
191 return data; 192 return data;
192} 193}
193 194
194void SkinCache::store( const QString &skinPath, const QString &fileNameInfix, SkinData *data ) 195void SkinCache::store( const QString &skinPath, const QString &fileNameInfix, SkinData *data )
195{ 196{
196 QPixmap *backgroundPixmap = new QPixmap( data->backgroundPixmap ); 197 QPixmap *backgroundPixmap = new QPixmap( data->backgroundPixmap );
197 198
198 data->backgroundPixmap = QPixmap(); 199 data->backgroundPixmap = QPixmap();
199 200
200 QString key = skinPath + fileNameInfix; 201 QString key = skinPath + fileNameInfix;
201 202
202 if ( m_cache.find( key, false /*ref*/ ) != 0 || 203 if ( m_cache.find( key, false /*ref*/ ) != 0 ||
203 !m_cache.insert( key, data ) ) 204 !m_cache.insert( key, data ) )
204 delete data; 205 delete data;
205 206
206 if ( m_backgroundPixmapCache.find( skinPath, false /*ref*/ ) != 0 || 207 if ( m_backgroundPixmapCache.find( skinPath, false /*ref*/ ) != 0 ||
207 !m_backgroundPixmapCache.insert( skinPath, backgroundPixmap ) ) 208 !m_backgroundPixmapCache.insert( skinPath, backgroundPixmap ) )
208 delete backgroundPixmap; 209 delete backgroundPixmap;
209} 210}
210 211
211SkinLoader::IncrementalLoader::IncrementalLoader( const Info &info ) 212SkinLoader::IncrementalLoader::IncrementalLoader( const Info &info )
212 : m_skin( info.skinName, info.fileNameInfix ), m_info( info ) 213 : m_skin( info.skinName, info.fileNameInfix ), m_info( info )
213{ 214{
214 m_currentState = LoadBackgroundPixmap; 215 m_currentState = LoadBackgroundPixmap;
215} 216}
216 217
217SkinLoader::IncrementalLoader::LoaderResult SkinLoader::IncrementalLoader::loadStep() 218SkinLoader::IncrementalLoader::LoaderResult SkinLoader::IncrementalLoader::loadStep()
218{ 219{
219 switch ( m_currentState ) { 220 switch ( m_currentState ) {
220 case LoadBackgroundPixmap: 221 case LoadBackgroundPixmap:
221 odebug << "load bgpixmap" << oendl; 222 odebug << "load bgpixmap" << oendl;
222 m_skin.backgroundPixmap(); 223 m_skin.backgroundPixmap();
223 m_currentState = LoadButtonUpImage; 224 m_currentState = LoadButtonUpImage;
224 break; 225 break;
225 case LoadButtonUpImage: 226 case LoadButtonUpImage:
226 odebug << "load upimage" << oendl; 227 odebug << "load upimage" << oendl;
227 m_skin.buttonUpImage(); 228 m_skin.buttonUpImage();
228 m_currentState = LoadButtonDownImage; 229 m_currentState = LoadButtonDownImage;
229 break; 230 break;
230 case LoadButtonDownImage: 231 case LoadButtonDownImage:
231 odebug << "load downimage" << oendl; 232 odebug << "load downimage" << oendl;
232 m_skin.buttonDownImage(); 233 m_skin.buttonDownImage();
233 m_currentState = LoadButtonMasks; 234 m_currentState = LoadButtonMasks;
234 m_currentButton = 0; 235 m_currentButton = 0;
235 break; 236 break;
236 case LoadButtonMasks: 237 case LoadButtonMasks:
237 odebug << "load button masks " << m_currentButton << "" << oendl; 238 odebug << "load button masks " << m_currentButton << "" << oendl;
238 m_skin.buttonMaskImage( m_info.buttonInfo[ m_currentButton ].fileName ); 239 m_skin.buttonMaskImage( m_info.buttonInfo[ m_currentButton ].fileName );
239 240
240 m_currentButton++; 241 m_currentButton++;
241 if ( m_currentButton >= m_info.buttonCount ) 242 if ( m_currentButton >= m_info.buttonCount )
242 m_currentState = LoadButtonMask; 243 m_currentState = LoadButtonMask;
243 244
244 break; 245 break;
245 case LoadButtonMask: 246 case LoadButtonMask:
246 odebug << "load whole mask" << oendl; 247 odebug << "load whole mask" << oendl;
247 m_skin.buttonMask( m_info.buttonInfo, m_info.buttonCount ); 248 m_skin.buttonMask( m_info.buttonInfo, m_info.buttonCount );
248 return LoadingCompleted; 249 return LoadingCompleted;
249 } 250 }
250 251
251 return MoreToCome; 252 return MoreToCome;
252} 253}
253 254
254SkinLoader::SkinLoader() 255SkinLoader::SkinLoader()
255 : m_currentLoader( 0 ), m_timerId( -1 ) 256 : m_currentLoader( 0 ), m_timerId( -1 )
256{ 257{
257} 258}
258 259
259SkinLoader::~SkinLoader() 260SkinLoader::~SkinLoader()
260{ 261{
261 odebug << "SkinLoader::~SkinLoader()" << oendl; 262 odebug << "SkinLoader::~SkinLoader()" << oendl;
262 killTimers(); 263 killTimers();
263 delete m_currentLoader; 264 delete m_currentLoader;
264} 265}
265 266
266void SkinLoader::schedule( const MediaWidget::GUIInfo &guiInfo ) 267void SkinLoader::schedule( const MediaWidget::GUIInfo &guiInfo )
267{ 268{
268 schedule( Skin::defaultSkinName(), guiInfo ); 269 schedule( Skin::defaultSkinName(), guiInfo );
269} 270}
270 271
271void SkinLoader::schedule( const QString &skinName, const MediaWidget::GUIInfo &guiInfo ) 272void SkinLoader::schedule( const QString &skinName, const MediaWidget::GUIInfo &guiInfo )
272{ 273{
273 pendingSkins << Info( skinName, guiInfo ); 274 pendingSkins << Info( skinName, guiInfo );
274} 275}
275 276
276void SkinLoader::start() 277void SkinLoader::start()
277{ 278{
278 assert( m_timerId == -1 ); 279 assert( m_timerId == -1 );
279 m_timerId = startTimer( 100 /* ms */ ); 280 m_timerId = startTimer( 100 /* ms */ );
280 odebug << "SkinLoader::start() " << pendingSkins.count() << " jobs" << oendl; 281 odebug << "SkinLoader::start() " << pendingSkins.count() << " jobs" << oendl;
281} 282}
282 283
283void SkinLoader::timerEvent( QTimerEvent *ev ) 284void SkinLoader::timerEvent( QTimerEvent *ev )
284{ 285{
285 if ( ev->timerId() != m_timerId ) { 286 if ( ev->timerId() != m_timerId ) {
286 QObject::timerEvent( ev ); 287 QObject::timerEvent( ev );
287 return; 288 return;
288 } 289 }
289 290
290 if ( !m_currentLoader ) { 291 if ( !m_currentLoader ) {
291 292
292 if ( pendingSkins.isEmpty() ) { 293 if ( pendingSkins.isEmpty() ) {
293 odebug << "all jobs done" << oendl; 294 odebug << "all jobs done" << oendl;
294 killTimer( m_timerId ); 295 killTimer( m_timerId );
295 m_timerId = -1; 296 m_timerId = -1;
296 // ### qt3: use deleteLater(); 297 // ### qt3: use deleteLater();
297 QTimer::singleShot( 0, this, SLOT( deleteMe() ) ); 298 QTimer::singleShot( 0, this, SLOT( deleteMe() ) );
298 return; 299 return;
299 } 300 }
300 301
301 Info nfo = *pendingSkins.begin(); 302 Info nfo = *pendingSkins.begin();
302 pendingSkins.remove( pendingSkins.begin() ); 303 pendingSkins.remove( pendingSkins.begin() );
303 304
304 m_currentLoader = new IncrementalLoader( nfo ); 305 m_currentLoader = new IncrementalLoader( nfo );
305 odebug << "new loader " << pendingSkins.count() << " jobs left" << oendl; 306 odebug << "new loader " << pendingSkins.count() << " jobs left" << oendl;
306 } 307 }
307 308
308 if ( m_currentLoader->loadStep() == IncrementalLoader::LoadingCompleted ) { 309 if ( m_currentLoader->loadStep() == IncrementalLoader::LoadingCompleted ) {
309 delete m_currentLoader; 310 delete m_currentLoader;
310 m_currentLoader = 0; 311 m_currentLoader = 0;
311 } 312 }
312 313
313 odebug << "finished step" << oendl; 314 odebug << "finished step" << oendl;
314} 315}
315 316
316void SkinLoader::deleteMe() 317void SkinLoader::deleteMe()
317{ 318{
318 delete this; 319 delete this;
319} 320}
320 321
321/* vim: et sw=4 ts=4 322/* vim: et sw=4 ts=4
322 */ 323 */
diff --git a/noncore/multimedia/opieplayer2/threadutil.cpp b/noncore/multimedia/opieplayer2/threadutil.cpp
index d8b8abe..6ed9853 100644
--- a/noncore/multimedia/opieplayer2/threadutil.cpp
+++ b/noncore/multimedia/opieplayer2/threadutil.cpp
@@ -1,394 +1,395 @@
1/* This file is part of the KDE project 1/* This file is part of the KDE project
2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org> 2 Copyright (C) 2002 Simon Hausmann <hausmann@kde.org>
3 3
4 This library is free software; you can redistribute it and/or 4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public 5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either 6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version. 7 version 2 of the License, or (at your option) any later version.
8 8
9 This library is distributed in the hope that it will be useful, 9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details. 12 Library General Public License for more details.
13 13
14 You should have received a copy of the GNU Library General Public License 14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to 15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. 17 Boston, MA 02111-1307, USA.
18*/ 18*/
19 19
20#include "threadutil.h" 20#include "threadutil.h"
21 21
22#include <opie2/odebug.h>
22#include <qsocketnotifier.h> 23#include <qsocketnotifier.h>
23 24
24#include <pthread.h> 25#include <pthread.h>
25#include <assert.h> 26#include <assert.h>
26#include <unistd.h> 27#include <unistd.h>
27#include <errno.h> 28#include <errno.h>
28 29
29using namespace ThreadUtil; 30using namespace ThreadUtil;
30 31
31struct Mutex::Data 32struct Mutex::Data
32{ 33{
33 Data() 34 Data()
34 { 35 {
35 pthread_mutex_init( &mutex, 0 ); 36 pthread_mutex_init( &mutex, 0 );
36 } 37 }
37 ~Data() 38 ~Data()
38 { 39 {
39 pthread_mutex_destroy( &mutex ); 40 pthread_mutex_destroy( &mutex );
40 } 41 }
41 42
42 pthread_mutex_t mutex; 43 pthread_mutex_t mutex;
43}; 44};
44 45
45Mutex::Mutex() 46Mutex::Mutex()
46 : d( new Data ) 47 : d( new Data )
47{ 48{
48} 49}
49 50
50Mutex::~Mutex() 51Mutex::~Mutex()
51{ 52{
52 delete d; 53 delete d;
53} 54}
54 55
55void Mutex::lock() 56void Mutex::lock()
56{ 57{
57 pthread_mutex_lock( &d->mutex ); 58 pthread_mutex_lock( &d->mutex );
58} 59}
59 60
60void Mutex::unlock() 61void Mutex::unlock()
61{ 62{
62 pthread_mutex_unlock( &d->mutex ); 63 pthread_mutex_unlock( &d->mutex );
63} 64}
64 65
65bool Mutex::tryLock() 66bool Mutex::tryLock()
66{ 67{
67 return pthread_mutex_trylock( &d->mutex ) == 0; 68 return pthread_mutex_trylock( &d->mutex ) == 0;
68} 69}
69 70
70bool Mutex::isLocked() 71bool Mutex::isLocked()
71{ 72{
72 if ( !tryLock() ) 73 if ( !tryLock() )
73 return true; 74 return true;
74 75
75 unlock(); 76 unlock();
76 return false; 77 return false;
77} 78}
78 79
79struct WaitCondition::Data 80struct WaitCondition::Data
80{ 81{
81 Data() 82 Data()
82 { 83 {
83 int result = pthread_cond_init( &waitCondition, 0 ); 84 int result = pthread_cond_init( &waitCondition, 0 );
84 assert( result == 0 ); 85 assert( result == 0 );
85 } 86 }
86 ~Data() 87 ~Data()
87 { 88 {
88 pthread_cond_destroy( &waitCondition ); 89 pthread_cond_destroy( &waitCondition );
89 } 90 }
90 91
91 pthread_cond_t waitCondition; 92 pthread_cond_t waitCondition;
92}; 93};
93 94
94WaitCondition::WaitCondition() 95WaitCondition::WaitCondition()
95 : d( new Data ) 96 : d( new Data )
96{ 97{
97} 98}
98 99
99WaitCondition::~WaitCondition() 100WaitCondition::~WaitCondition()
100{ 101{
101 delete d; 102 delete d;
102} 103}
103 104
104bool WaitCondition::wait() 105bool WaitCondition::wait()
105{ 106{
106 Mutex m; 107 Mutex m;
107 m.lock(); 108 m.lock();
108 return wait( m ); 109 return wait( m );
109} 110}
110 111
111bool WaitCondition::wait( Mutex &mutex ) 112bool WaitCondition::wait( Mutex &mutex )
112{ 113{
113 return pthread_cond_wait( &d->waitCondition, &mutex.d->mutex ); 114 return pthread_cond_wait( &d->waitCondition, &mutex.d->mutex );
114} 115}
115 116
116void WaitCondition::wakeOne() 117void WaitCondition::wakeOne()
117{ 118{
118 pthread_cond_signal( &d->waitCondition ); 119 pthread_cond_signal( &d->waitCondition );
119} 120}
120 121
121void WaitCondition::wakeAll() 122void WaitCondition::wakeAll()
122{ 123{
123 pthread_cond_broadcast( &d->waitCondition ); 124 pthread_cond_broadcast( &d->waitCondition );
124} 125}
125 126
126struct Thread::Data 127struct Thread::Data
127{ 128{
128 Data() : isRunning( false ) 129 Data() : isRunning( false )
129 {} 130 {}
130 131
131 pthread_t self; 132 pthread_t self;
132 Mutex guard; 133 Mutex guard;
133 bool isRunning; 134 bool isRunning;
134 135
135 WaitCondition finishCondition; 136 WaitCondition finishCondition;
136 137
137 Thread *thr; 138 Thread *thr;
138 139
139 void run() { thr->run(); } 140 void run() { thr->run(); }
140}; 141};
141 142
142extern "C" 143extern "C"
143{ 144{
144 145
145static void terminate_thread( void *arg ) 146static void terminate_thread( void *arg )
146{ 147{
147 Thread::Data *data = ( Thread::Data* )arg; 148 Thread::Data *data = ( Thread::Data* )arg;
148 149
149 assert( data ); 150 assert( data );
150 151
151 AutoLock locker( data->guard ); 152 AutoLock locker( data->guard );
152 data->isRunning = false; 153 data->isRunning = false;
153 data->finishCondition.wakeAll(); 154 data->finishCondition.wakeAll();
154} 155}
155 156
156static void *start_thread( void *arg ) 157static void *start_thread( void *arg )
157{ 158{
158 Thread::Data *data = ( Thread::Data* )arg; 159 Thread::Data *data = ( Thread::Data* )arg;
159 160
160 pthread_cleanup_push( terminate_thread, data ); 161 pthread_cleanup_push( terminate_thread, data );
161 162
162 data->isRunning = true; 163 data->isRunning = true;
163 data->run(); 164 data->run();
164 165
165 pthread_cleanup_pop( true ); 166 pthread_cleanup_pop( true );
166 167
167 Thread::exit(); 168 Thread::exit();
168 return 0; // never reached 169 return 0; // never reached
169} 170}
170 171
171} 172}
172 173
173Thread::Thread() 174Thread::Thread()
174 : d( new Data ) 175 : d( new Data )
175{ 176{
176 d->thr = this; 177 d->thr = this;
177} 178}
178 179
179Thread::~Thread() 180Thread::~Thread()
180{ 181{
181 assert( d->isRunning == false ); 182 assert( d->isRunning == false );
182 delete d; 183 delete d;
183} 184}
184 185
185void Thread::start() 186void Thread::start()
186{ 187{
187 AutoLock lock( d->guard ); 188 AutoLock lock( d->guard );
188 189
189 if ( d->isRunning ) { 190 if ( d->isRunning ) {
190 odebug << "ThreadUtil::Thread::start() called for running thread." << oendl; 191 odebug << "ThreadUtil::Thread::start() called for running thread." << oendl;
191 return; 192 return;
192 } 193 }
193 194
194 pthread_attr_t attributes; 195 pthread_attr_t attributes;
195 pthread_attr_init( &attributes ); 196 pthread_attr_init( &attributes );
196 pthread_attr_setscope( &attributes, PTHREAD_SCOPE_SYSTEM ); 197 pthread_attr_setscope( &attributes, PTHREAD_SCOPE_SYSTEM );
197 int err = pthread_create( &d->self, &attributes, start_thread, ( void* )d ); 198 int err = pthread_create( &d->self, &attributes, start_thread, ( void* )d );
198 if ( err != 0 ) { 199 if ( err != 0 ) {
199 odebug << "ThreadUtil::Thread::start() : can't create thread: " << strerror( err ) << "" << oendl; 200 odebug << "ThreadUtil::Thread::start() : can't create thread: " << strerror( err ) << "" << oendl;
200 pthread_attr_destroy( &attributes ); 201 pthread_attr_destroy( &attributes );
201 return; 202 return;
202 } 203 }
203 pthread_attr_destroy( &attributes ); 204 pthread_attr_destroy( &attributes );
204} 205}
205 206
206void Thread::terminate() 207void Thread::terminate()
207{ 208{
208 AutoLock lock( d->guard ); 209 AutoLock lock( d->guard );
209 if ( !d->isRunning ) 210 if ( !d->isRunning )
210 return; 211 return;
211 212
212 pthread_cancel( d->self ); 213 pthread_cancel( d->self );
213} 214}
214 215
215bool Thread::wait() 216bool Thread::wait()
216{ 217{
217 AutoLock lock( d->guard ); 218 AutoLock lock( d->guard );
218 if ( !d->isRunning ) 219 if ( !d->isRunning )
219 return true; 220 return true;
220 221
221 return d->finishCondition.wait( d->guard ); 222 return d->finishCondition.wait( d->guard );
222} 223}
223 224
224bool Thread::isRunning() const 225bool Thread::isRunning() const
225{ 226{
226 AutoLock lock( d->guard ); 227 AutoLock lock( d->guard );
227 return d->isRunning; 228 return d->isRunning;
228} 229}
229 230
230void Thread::exit() 231void Thread::exit()
231{ 232{
232 pthread_exit( 0 ); 233 pthread_exit( 0 );
233} 234}
234 235
235OnewayNotifier::OnewayNotifier() 236OnewayNotifier::OnewayNotifier()
236{ 237{
237 int fds[ 2 ]; 238 int fds[ 2 ];
238 pipe( fds ); 239 pipe( fds );
239 m_readFd = fds[ 0 ]; 240 m_readFd = fds[ 0 ];
240 m_writeFd = fds[ 1 ]; 241 m_writeFd = fds[ 1 ];
241 242
242 m_notifier = new QSocketNotifier( m_readFd, QSocketNotifier::Read ); 243 m_notifier = new QSocketNotifier( m_readFd, QSocketNotifier::Read );
243 connect( m_notifier, SIGNAL( activated(int) ), 244 connect( m_notifier, SIGNAL( activated(int) ),
244 this, SLOT( wakeUp() ) ); 245 this, SLOT( wakeUp() ) );
245} 246}
246 247
247OnewayNotifier::~OnewayNotifier() 248OnewayNotifier::~OnewayNotifier()
248{ 249{
249 delete m_notifier; 250 delete m_notifier;
250 251
251 ::close( m_readFd ); 252 ::close( m_readFd );
252 ::close( m_writeFd ); 253 ::close( m_writeFd );
253} 254}
254 255
255void OnewayNotifier::notify() 256void OnewayNotifier::notify()
256{ 257{
257 const char c = 42; 258 const char c = 42;
258 ::write( m_writeFd, &c, 1 ); 259 ::write( m_writeFd, &c, 1 );
259} 260}
260 261
261void OnewayNotifier::wakeUp() 262void OnewayNotifier::wakeUp()
262{ 263{
263 char c = 0; 264 char c = 0;
264 265
265 if ( ::read( m_readFd, &c, 1 ) != 1 ) 266 if ( ::read( m_readFd, &c, 1 ) != 1 )
266 return; 267 return;
267 268
268 emit awake(); 269 emit awake();
269} 270}
270 271
271ChannelMessage::ChannelMessage( int type ) 272ChannelMessage::ChannelMessage( int type )
272 : m_type( type ), m_isCall( false ), m_replied( false ), 273 : m_type( type ), m_isCall( false ), m_replied( false ),
273 m_inEventHandler( false ) 274 m_inEventHandler( false )
274{ 275{
275} 276}
276 277
277ChannelMessage::~ChannelMessage() 278ChannelMessage::~ChannelMessage()
278{ 279{
279 if ( m_guard.isLocked() ) 280 if ( m_guard.isLocked() )
280 m_guard.unlock(); 281 m_guard.unlock();
281} 282}
282 283
283void ChannelMessage::reply() 284void ChannelMessage::reply()
284{ 285{
285 if ( !m_isCall ) 286 if ( !m_isCall )
286 { 287 {
287 odebug << "ChannelMessage::reply() - can't reply oneway message!" << oendl; 288 odebug << "ChannelMessage::reply() - can't reply oneway message!" << oendl;
288 return; 289 return;
289 } 290 }
290 291
291 if ( m_inEventHandler ) 292 if ( m_inEventHandler )
292 { 293 {
293 m_replied = true; 294 m_replied = true;
294 return; 295 return;
295 } 296 }
296 297
297 m_condition.wakeOne(); 298 m_condition.wakeOne();
298 m_guard.unlock(); 299 m_guard.unlock();
299} 300}
300 301
301struct Channel::Private 302struct Channel::Private
302{ 303{
303 Private() 304 Private()
304 { 305 {
305 ownerThread = pthread_self(); 306 ownerThread = pthread_self();
306 } 307 }
307 308
308 pthread_t ownerThread; 309 pthread_t ownerThread;
309}; 310};
310 311
311Channel::Channel( QObject *parent, const char *name ) 312Channel::Channel( QObject *parent, const char *name )
312 : QObject( parent, name ), d( new Private ) 313 : QObject( parent, name ), d( new Private )
313{ 314{
314 connect( &m_notifier, SIGNAL( awake() ), 315 connect( &m_notifier, SIGNAL( awake() ),
315 this, SLOT( deliver() ) ); 316 this, SLOT( deliver() ) );
316} 317}
317 318
318Channel::~Channel() 319Channel::~Channel()
319{ 320{
320 delete d; 321 delete d;
321} 322}
322 323
323void Channel::send( ChannelMessage *message, SendType type ) 324void Channel::send( ChannelMessage *message, SendType type )
324{ 325{
325 if ( type == WaitForReply ) 326 if ( type == WaitForReply )
326 { 327 {
327 message->m_guard.lock(); 328 message->m_guard.lock();
328 message->m_isCall = true; 329 message->m_isCall = true;
329 } 330 }
330 331
331 m_pendingMessagesGuard.lock(); 332 m_pendingMessagesGuard.lock();
332 m_pendingMessages << MsgEnvelope( type, message ); 333 m_pendingMessages << MsgEnvelope( type, message );
333 m_pendingMessagesGuard.unlock(); 334 m_pendingMessagesGuard.unlock();
334 335
335 if ( d->ownerThread == pthread_self() ) { 336 if ( d->ownerThread == pthread_self() ) {
336 assert( type != WaitForReply ); 337 assert( type != WaitForReply );
337 338
338 deliver(); 339 deliver();
339 } 340 }
340 else 341 else
341 m_notifier.notify(); 342 m_notifier.notify();
342 //QThread::postEvent( this, new QCustomEvent( QEvent::User, envelope ) ); 343 //QThread::postEvent( this, new QCustomEvent( QEvent::User, envelope ) );
343 344
344 if ( type == WaitForReply ) 345 if ( type == WaitForReply )
345 { 346 {
346 message->m_condition.wait( message->m_guard ); 347 message->m_condition.wait( message->m_guard );
347 message->m_guard.unlock(); 348 message->m_guard.unlock();
348 } 349 }
349} 350}
350 351
351void Channel::deliver() 352void Channel::deliver()
352{ 353{
353 AutoLock lock( m_pendingMessagesGuard ); 354 AutoLock lock( m_pendingMessagesGuard );
354 355
355 while ( !m_pendingMessages.isEmpty() ) { 356 while ( !m_pendingMessages.isEmpty() ) {
356 MsgEnvelope envelope = m_pendingMessages.first(); 357 MsgEnvelope envelope = m_pendingMessages.first();
357 358
358 m_pendingMessages.remove( m_pendingMessages.begin() ); 359 m_pendingMessages.remove( m_pendingMessages.begin() );
359 360
360 m_pendingMessagesGuard.unlock(); 361 m_pendingMessagesGuard.unlock();
361 deliverOne( envelope ); 362 deliverOne( envelope );
362 m_pendingMessagesGuard.lock(); 363 m_pendingMessagesGuard.lock();
363 } 364 }
364} 365}
365 366
366void Channel::deliverOne( const MsgEnvelope &envelope ) 367void Channel::deliverOne( const MsgEnvelope &envelope )
367{ 368{
368 ChannelMessage *msg = envelope.msg; 369 ChannelMessage *msg = envelope.msg;
369 370
370 assert( msg ); 371 assert( msg );
371 372
372 if ( envelope.type == WaitForReply ) 373 if ( envelope.type == WaitForReply )
373 { 374 {
374 msg->m_guard.lock(); 375 msg->m_guard.lock();
375 msg->m_inEventHandler = true; 376 msg->m_inEventHandler = true;
376 } 377 }
377 378
378 receiveMessage( msg, envelope.type ); 379 receiveMessage( msg, envelope.type );
379 380
380 if ( envelope.type == WaitForReply ) 381 if ( envelope.type == WaitForReply )
381 { 382 {
382 msg->m_inEventHandler = false; 383 msg->m_inEventHandler = false;
383 if ( msg->m_replied ) 384 if ( msg->m_replied )
384 { 385 {
385 msg->m_condition.wakeOne(); 386 msg->m_condition.wakeOne();
386 // this is a bit tricky. we unlock only when we reply. 387 // this is a bit tricky. we unlock only when we reply.
387 // reply() does an unlock as well. 388 // reply() does an unlock as well.
388 msg->m_guard.unlock(); 389 msg->m_guard.unlock();
389 } 390 }
390 } 391 }
391} 392}
392 393
393/* vim: et sw=4 ts=4 394/* vim: et sw=4 ts=4
394 */ 395 */