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 <Looper.h>
40#include <OS.h>
41
42#include "ObjectList.h"
43#include "FunctionObject.h"
44
45
46namespace BPrivate {
47
48class MessengerAutoLocker {
49	// move this into AutoLock.h
50	public:
51		MessengerAutoLocker(BMessenger* messenger)
52			:	fMessenger(messenger),
53				fHasLock(messenger->LockTarget())
54		{}
55
56		~MessengerAutoLocker()
57		{
58			Unlock();
59		}
60
61		bool operator!() const
62		{
63			return !fHasLock;
64		}
65
66		bool IsLocked() const
67		{
68			return fHasLock;
69		}
70
71		void Unlock()
72		{
73			if (fHasLock) {
74				BLooper* looper;
75				fMessenger->Target(&looper);
76				if (looper)
77					looper->Unlock();
78				fHasLock = false;
79			}
80		}
81
82	private:
83		BMessenger* fMessenger;
84		bool fHasLock;
85};
86
87
88class SimpleThread {
89	// this should only be used as a base class,
90	// subclass needs to add proper locking mechanism
91public:
92	SimpleThread(int32 priority = B_LOW_PRIORITY, const char* name = 0);
93	virtual ~SimpleThread();
94
95	void Go();
96
97private:
98	static status_t RunBinder(void*);
99	virtual void Run() = 0;
100
101protected:
102	thread_id fScanThread;
103	int32 fPriority;
104	const char* fName;
105};
106
107
108class Thread : private SimpleThread {
109public:
110	static void Launch(FunctionObject* functor,
111		int32 priority = B_LOW_PRIORITY, const char* name = 0);
112
113private:
114	Thread(FunctionObject*, int32 priority, const char* name);
115	~Thread();
116	virtual void Run();
117
118	FunctionObject* fFunctor;
119};
120
121
122class ThreadSequence : private SimpleThread {
123public:
124	static void Launch(BObjectList<FunctionObject>*, bool async = true,
125		int32 priority = B_LOW_PRIORITY);
126
127private:
128	ThreadSequence(BObjectList<FunctionObject>*, int32 priority);
129	~ThreadSequence();
130
131	virtual void Run();
132	static void Run(BObjectList<FunctionObject>*list);
133
134	BObjectList<FunctionObject>* fFunctorList;
135};
136
137
138// would use SingleParamFunctionObjectWithResult, except mwcc won't handle this
139template <class Param1>
140class SingleParamFunctionObjectWorkaround : public
141	FunctionObjectWithResult<status_t> {
142public:
143	SingleParamFunctionObjectWorkaround(
144		status_t (*function)(Param1), Param1 param1)
145		:	fFunction(function),
146			fParam1(param1)
147		{
148		}
149
150	virtual void operator()()
151		{ (fFunction)(fParam1); }
152
153	virtual ulong Size() const { return sizeof(*this); }
154
155private:
156	status_t (*fFunction)(Param1);
157	Param1 fParam1;
158};
159
160
161template <class T>
162class SimpleMemberFunctionObjectWorkaround : public
163	FunctionObjectWithResult<status_t> {
164public:
165	SimpleMemberFunctionObjectWorkaround(status_t (T::*function)(), T* onThis)
166		:	fFunction(function),
167			fOnThis(onThis)
168		{
169		}
170
171	virtual void operator()()
172		{ (fOnThis->*fFunction)(); }
173
174	virtual ulong Size() const { return sizeof(*this); }
175
176private:
177	status_t (T::*fFunction)();
178	T fOnThis;
179};
180
181
182template <class Param1, class Param2>
183class TwoParamFunctionObjectWorkaround : public
184	FunctionObjectWithResult<status_t>  {
185public:
186	TwoParamFunctionObjectWorkaround(status_t (*callThis)(Param1, Param2),
187		Param1 param1, Param2 param2)
188		:	function(callThis),
189			fParam1(param1),
190			fParam2(param2)
191		{
192		}
193
194	virtual void operator()()
195		{ (function)(fParam1, fParam2); }
196
197	virtual uint32 Size() const { return sizeof(*this); }
198
199private:
200	status_t (*function)(Param1, Param2);
201	Param1 fParam1;
202	Param2 fParam2;
203};
204
205
206template <class Param1, class Param2, class Param3>
207class ThreeParamFunctionObjectWorkaround : public
208	FunctionObjectWithResult<status_t>  {
209public:
210	ThreeParamFunctionObjectWorkaround(
211		status_t (*callThis)(Param1, Param2, Param3),
212		Param1 param1, Param2 param2, Param3 param3)
213		:	function(callThis),
214			fParam1(param1),
215			fParam2(param2),
216			fParam3(param3)
217		{
218		}
219
220	virtual void operator()()
221		{ (function)(fParam1, fParam2, fParam3); }
222
223	virtual uint32 Size() const { return sizeof(*this); }
224
225private:
226	status_t (*function)(Param1, Param2, Param3);
227	Param1 fParam1;
228	Param2 fParam2;
229	Param3 fParam3;
230};
231
232
233template <class Param1, class Param2, class Param3, class Param4>
234class FourParamFunctionObjectWorkaround : public
235	FunctionObjectWithResult<status_t>  {
236public:
237	FourParamFunctionObjectWorkaround(
238		status_t (*callThis)(Param1, Param2, Param3, Param4),
239		Param1 param1, Param2 param2, Param3 param3, Param4 param4)
240		:	function(callThis),
241			fParam1(param1),
242			fParam2(param2),
243			fParam3(param3),
244			fParam4(param4)
245		{
246		}
247
248	virtual void operator()()
249		{ (function)(fParam1, fParam2, fParam3, fParam4); }
250
251	virtual uint32 Size() const { return sizeof(*this); }
252
253private:
254	status_t (*function)(Param1, Param2, Param3, Param4);
255	Param1 fParam1;
256	Param2 fParam2;
257	Param3 fParam3;
258	Param4 fParam4;
259};
260
261
262template<class Param1>
263void
264LaunchInNewThread(const char* name, int32 priority, status_t (*func)(Param1),
265	Param1 p1)
266{
267	Thread::Launch(new SingleParamFunctionObjectWorkaround<Param1>(func, p1),
268		priority, name);
269}
270
271
272template<class T>
273void
274LaunchInNewThread(const char* name, int32 priority, status_t (T::*function)(),
275	T* onThis)
276{
277	Thread::Launch(new SimpleMemberFunctionObjectWorkaround<T>(function,
278		onThis), priority, name);
279}
280
281
282template<class Param1, class Param2>
283void
284LaunchInNewThread(const char* name, int32 priority,
285	status_t (*func)(Param1, Param2),
286	Param1 p1, Param2 p2)
287{
288	Thread::Launch(new
289		TwoParamFunctionObjectWorkaround<Param1, Param2>(func, p1, p2),
290			priority, name);
291}
292
293
294template<class Param1, class Param2, class Param3>
295void
296LaunchInNewThread(const char* name, int32 priority,
297	status_t (*func)(Param1, Param2, Param3),
298	Param1 p1, Param2 p2, Param3 p3)
299{
300	Thread::Launch(new ThreeParamFunctionObjectWorkaround<Param1, Param2,
301		Param3>(func, p1, p2, p3), priority, name);
302}
303
304
305template<class Param1, class Param2, class Param3, class Param4>
306void
307LaunchInNewThread(const char* name, int32 priority,
308	status_t (*func)(Param1, Param2, Param3, Param4),
309	Param1 p1, Param2 p2, Param3 p3, Param4 p4)
310{
311	Thread::Launch(new FourParamFunctionObjectWorkaround<Param1, Param2,
312		Param3, Param4>(func, p1, p2, p3, p4), priority, name);
313}
314
315
316template<class View>
317class MouseDownThread {
318public:
319	static void TrackMouse(View* view, void (View::*)(BPoint),
320		void (View::*)(BPoint, uint32) = 0,
321		bigtime_t pressingPeriod = 100000);
322
323protected:
324	MouseDownThread(View* view, void (View::*)(BPoint),
325		void (View::*)(BPoint, uint32), bigtime_t pressingPeriod);
326
327	virtual ~MouseDownThread();
328
329	void Go();
330	virtual void Track();
331
332	static status_t TrackBinder(void*);
333
334private:
335	BMessenger fOwner;
336	void (View::*fDonePressing)(BPoint);
337	void (View::*fPressing)(BPoint, uint32);
338	bigtime_t fPressingPeriod;
339	volatile thread_id fThreadID;
340};
341
342
343template<class View>
344void
345MouseDownThread<View>::TrackMouse(View* view,
346	void(View::*donePressing)(BPoint),
347	void(View::*pressing)(BPoint, uint32), bigtime_t pressingPeriod)
348{
349	(new MouseDownThread(view, donePressing, pressing, pressingPeriod))->Go();
350}
351
352
353template<class View>
354MouseDownThread<View>::MouseDownThread(View* view,
355	void (View::*donePressing)(BPoint),
356	void (View::*pressing)(BPoint, uint32), bigtime_t pressingPeriod)
357	:	fOwner(view, view->Window()),
358		fDonePressing(donePressing),
359		fPressing(pressing),
360		fPressingPeriod(pressingPeriod)
361{
362}
363
364
365template<class View>
366MouseDownThread<View>::~MouseDownThread()
367{
368}
369
370
371template<class View>
372void
373MouseDownThread<View>::Go()
374{
375	fThreadID = spawn_thread(&MouseDownThread::TrackBinder,
376		"MouseTrackingThread", B_NORMAL_PRIORITY, this);
377
378	if (fThreadID <= 0 || resume_thread(fThreadID) != B_OK)
379		// didn't start, don't leak self
380		delete this;
381}
382
383
384template<class View>
385status_t
386MouseDownThread<View>::TrackBinder(void* castToThis)
387{
388	MouseDownThread* self = static_cast<MouseDownThread*>(castToThis);
389	self->Track();
390	// dead at this point
391	return B_OK;
392}
393
394
395template<class View>
396void
397MouseDownThread<View>::Track()
398{
399	for (;;) {
400		MessengerAutoLocker lock(&fOwner);
401		if (!lock)
402			break;
403
404		BLooper* looper;
405		View* view = dynamic_cast<View*>(fOwner.Target(&looper));
406		if (!view)
407			break;
408
409		uint32 buttons;
410		BPoint location;
411		view->GetMouse(&location, &buttons, false);
412		if (!buttons) {
413			(view->*fDonePressing)(location);
414			break;
415		}
416		if (fPressing)
417			(view->*fPressing)(location, buttons);
418
419		lock.Unlock();
420		snooze(fPressingPeriod);
421	}
422
423	delete this;
424}
425
426
427} // namespace BPrivate
428
429using namespace BPrivate;
430
431#endif	// __THREAD__
432