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