1/* 2Open Tracker License 3 4Terms and Conditions 5 6Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a copy of 9this software and associated documentation files (the "Software"), to deal in 10the Software without restriction, including without limitation the rights to 11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12of the Software, and to permit persons to whom the Software is furnished to do 13so, subject to the following conditions: 14 15The above copyright notice and this permission notice applies to all licensees 16and shall be included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of Be Incorporated shall not be 26used in advertising or otherwise to promote the sale, use or other dealings in 27this Software without prior written authorization from Be Incorporated. 28 29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30of Be Incorporated in the United States and other countries. Other brand product 31names are registered trademarks or trademarks of their respective holders. 32All rights reserved. 33*/ 34#ifndef __THREAD__ 35#define __THREAD__ 36 37 38#include <Debug.h> 39#include <OS.h> 40 41#include "ObjectList.h" 42#include "FunctionObject.h" 43#include "Utilities.h" 44 45 46namespace BPrivate { 47 48class SimpleThread { 49 // this should only be used as a base class, 50 // subclass needs to add proper locking mechanism 51public: 52 SimpleThread(int32 priority = B_LOW_PRIORITY, const char* name = 0); 53 virtual ~SimpleThread(); 54 55 void Go(); 56 57private: 58 static status_t RunBinder(void*); 59 virtual void Run() = 0; 60 61protected: 62 thread_id fScanThread; 63 int32 fPriority; 64 const char* fName; 65}; 66 67 68class Thread : private SimpleThread { 69public: 70 static void Launch(FunctionObject* functor, 71 int32 priority = B_LOW_PRIORITY, const char* name = 0); 72 73private: 74 Thread(FunctionObject*, int32 priority, const char* name); 75 ~Thread(); 76 virtual void Run(); 77 78 FunctionObject* fFunctor; 79}; 80 81class ThreadSequence : private SimpleThread { 82public: 83 static void Launch(BObjectList<FunctionObject>*, bool async = true, 84 int32 priority = B_LOW_PRIORITY); 85 86private: 87 ThreadSequence(BObjectList<FunctionObject>*, int32 priority); 88 ~ThreadSequence(); 89 90 virtual void Run(); 91 static void Run(BObjectList<FunctionObject>*list); 92 93 BObjectList<FunctionObject>* fFunctorList; 94}; 95 96// would use SingleParamFunctionObjectWithResult, except mwcc won't handle this 97template <class Param1> 98class SingleParamFunctionObjectWorkaround : public 99 FunctionObjectWithResult<status_t> { 100public: 101 SingleParamFunctionObjectWorkaround( 102 status_t (*function)(Param1), Param1 param1) 103 : fFunction(function), 104 fParam1(param1) 105 { 106 } 107 108 109 virtual void operator()() 110 { (fFunction)(fParam1); } 111 112 virtual ulong Size() const { return sizeof(*this); } 113 114private: 115 status_t (*fFunction)(Param1); 116 Param1 fParam1; 117}; 118 119template <class T> 120class SimpleMemberFunctionObjectWorkaround : public 121 FunctionObjectWithResult<status_t> { 122public: 123 SimpleMemberFunctionObjectWorkaround(status_t (T::*function)(), T* onThis) 124 : fFunction(function), 125 fOnThis(onThis) 126 { 127 } 128 129 virtual void operator()() 130 { (fOnThis->*fFunction)(); } 131 132 virtual ulong Size() const { return sizeof(*this); } 133 134private: 135 status_t (T::*fFunction)(); 136 T fOnThis; 137}; 138 139 140template <class Param1, class Param2> 141class TwoParamFunctionObjectWorkaround : public 142 FunctionObjectWithResult<status_t> { 143public: 144 TwoParamFunctionObjectWorkaround(status_t (*callThis)(Param1, Param2), 145 Param1 param1, Param2 param2) 146 : function(callThis), 147 fParam1(param1), 148 fParam2(param2) 149 { 150 } 151 152 virtual void operator()() 153 { (function)(fParam1, fParam2); } 154 155 virtual uint32 Size() const { return sizeof(*this); } 156 157private: 158 status_t (*function)(Param1, Param2); 159 Param1 fParam1; 160 Param2 fParam2; 161}; 162 163 164template <class Param1, class Param2, class Param3> 165class ThreeParamFunctionObjectWorkaround : public 166 FunctionObjectWithResult<status_t> { 167public: 168 ThreeParamFunctionObjectWorkaround( 169 status_t (*callThis)(Param1, Param2, Param3), 170 Param1 param1, Param2 param2, Param3 param3) 171 : function(callThis), 172 fParam1(param1), 173 fParam2(param2), 174 fParam3(param3) 175 { 176 } 177 178 virtual void operator()() 179 { (function)(fParam1, fParam2, fParam3); } 180 181 virtual uint32 Size() const { return sizeof(*this); } 182 183private: 184 status_t (*function)(Param1, Param2, Param3); 185 Param1 fParam1; 186 Param2 fParam2; 187 Param3 fParam3; 188}; 189 190 191template <class Param1, class Param2, class Param3, class Param4> 192class FourParamFunctionObjectWorkaround : public 193 FunctionObjectWithResult<status_t> { 194public: 195 FourParamFunctionObjectWorkaround( 196 status_t (*callThis)(Param1, Param2, Param3, Param4), 197 Param1 param1, Param2 param2, Param3 param3, Param4 param4) 198 : function(callThis), 199 fParam1(param1), 200 fParam2(param2), 201 fParam3(param3), 202 fParam4(param4) 203 { 204 } 205 206 virtual void operator()() 207 { (function)(fParam1, fParam2, fParam3, fParam4); } 208 209 virtual uint32 Size() const { return sizeof(*this); } 210 211private: 212 status_t (*function)(Param1, Param2, Param3, Param4); 213 Param1 fParam1; 214 Param2 fParam2; 215 Param3 fParam3; 216 Param4 fParam4; 217}; 218 219 220template<class Param1> 221void 222LaunchInNewThread(const char* name, int32 priority, status_t (*func)(Param1), 223 Param1 p1) 224{ 225 Thread::Launch(new SingleParamFunctionObjectWorkaround<Param1>(func, p1), 226 priority, name); 227} 228 229 230template<class T> 231void 232LaunchInNewThread(const char* name, int32 priority, status_t (T::*function)(), 233 T* onThis) 234{ 235 Thread::Launch(new SimpleMemberFunctionObjectWorkaround<T>(function, 236 onThis), priority, name); 237} 238 239 240template<class Param1, class Param2> 241void 242LaunchInNewThread(const char* name, int32 priority, 243 status_t (*func)(Param1, Param2), 244 Param1 p1, Param2 p2) 245{ 246 Thread::Launch(new 247 TwoParamFunctionObjectWorkaround<Param1, Param2>(func, p1, p2), 248 priority, name); 249} 250 251 252template<class Param1, class Param2, class Param3> 253void 254LaunchInNewThread(const char* name, int32 priority, 255 status_t (*func)(Param1, Param2, Param3), 256 Param1 p1, Param2 p2, Param3 p3) 257{ 258 Thread::Launch(new ThreeParamFunctionObjectWorkaround<Param1, Param2, 259 Param3>(func, p1, p2, p3), priority, name); 260} 261 262 263template<class Param1, class Param2, class Param3, class Param4> 264void 265LaunchInNewThread(const char* name, int32 priority, 266 status_t (*func)(Param1, Param2, Param3, Param4), 267 Param1 p1, Param2 p2, Param3 p3, Param4 p4) 268{ 269 Thread::Launch(new FourParamFunctionObjectWorkaround<Param1, Param2, 270 Param3, Param4>(func, p1, p2, p3, p4), priority, name); 271} 272 273 274template<class View> 275class MouseDownThread { 276public: 277 static void TrackMouse(View* view, void (View::*)(BPoint), 278 void (View::*)(BPoint, uint32) = 0, 279 bigtime_t pressingPeriod = 100000); 280 281protected: 282 MouseDownThread(View* view, void (View::*)(BPoint), 283 void (View::*)(BPoint, uint32), bigtime_t pressingPeriod); 284 285 virtual ~MouseDownThread(); 286 287 void Go(); 288 virtual void Track(); 289 290 static status_t TrackBinder(void*); 291 292private: 293 BMessenger fOwner; 294 void (View::*fDonePressing)(BPoint); 295 void (View::*fPressing)(BPoint, uint32); 296 bigtime_t fPressingPeriod; 297 volatile thread_id fThreadID; 298}; 299 300 301template<class View> 302void 303MouseDownThread<View>::TrackMouse(View* view, 304 void(View::*donePressing)(BPoint), 305 void(View::*pressing)(BPoint, uint32), bigtime_t pressingPeriod) 306{ 307 (new MouseDownThread(view, donePressing, pressing, pressingPeriod))->Go(); 308} 309 310 311template<class View> 312MouseDownThread<View>::MouseDownThread(View* view, 313 void (View::*donePressing)(BPoint), 314 void (View::*pressing)(BPoint, uint32), bigtime_t pressingPeriod) 315 : fOwner(view, view->Window()), 316 fDonePressing(donePressing), 317 fPressing(pressing), 318 fPressingPeriod(pressingPeriod) 319{ 320} 321 322 323template<class View> 324MouseDownThread<View>::~MouseDownThread() 325{ 326 if (fThreadID > 0) { 327 kill_thread(fThreadID); 328 // dead at this point 329 TRESPASS(); 330 } 331} 332 333 334template<class View> 335void 336MouseDownThread<View>::Go() 337{ 338 fThreadID = spawn_thread(&MouseDownThread::TrackBinder, 339 "MouseTrackingThread", B_NORMAL_PRIORITY, this); 340 341 if (fThreadID <= 0 || resume_thread(fThreadID) != B_OK) 342 // didn't start, don't leak self 343 delete this; 344} 345 346 347template<class View> 348status_t 349MouseDownThread<View>::TrackBinder(void* castToThis) 350{ 351 MouseDownThread* self = static_cast<MouseDownThread*>(castToThis); 352 self->Track(); 353 // dead at this point 354 TRESPASS(); 355 return B_OK; 356} 357 358 359template<class View> 360void 361MouseDownThread<View>::Track() 362{ 363 for (;;) { 364 MessengerAutoLocker lock(&fOwner); 365 if (!lock) 366 break; 367 368 BLooper* looper; 369 View* view = dynamic_cast<View*>(fOwner.Target(&looper)); 370 if (!view) 371 break; 372 373 uint32 buttons; 374 BPoint location; 375 view->GetMouse(&location, &buttons, false); 376 if (!buttons) { 377 (view->*fDonePressing)(location); 378 break; 379 } 380 if (fPressing) 381 (view->*fPressing)(location, buttons); 382 383 lock.Unlock(); 384 snooze(fPressingPeriod); 385 } 386 387 delete this; 388 ASSERT(!"should not be here"); 389} 390 391} // namespace BPrivate 392 393using namespace BPrivate; 394 395#endif // __THREAD__ 396