xref: /haiku/src/kits/game/DirectWindow.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2003-2006, Haiku Inc.
3  * Authors:
4  *		Stefano Ceccherini (burton666@libero.it).
5  *		Carwyn Jones (turok2@currantbun.com)
6  *
7  * Distributed under the terms of the MIT License.
8  */
9 
10 
11 #include <DirectWindow.h>
12 #include <Screen.h>
13 
14 #include <clipping.h>
15 #include <AppServerLink.h>
16 #include <DirectWindowPrivate.h>
17 #include <ServerProtocol.h>
18 
19 
20 // We don't need this kind of locking, since the directDaemonFunc
21 // doesn't access critical shared data.
22 #define DW_NEEDS_LOCKING 0
23 
24 enum dw_status_bits {
25 	DW_STATUS_AREA_CLONED	 = 0x1,
26 	DW_STATUS_THREAD_STARTED = 0x2,
27 	DW_STATUS_SEM_CREATED	 = 0x4
28 };
29 
30 
31 BDirectWindow::BDirectWindow(BRect frame, const char *title, window_type type,
32 	uint32 flags, uint32 workspace)
33 	: BWindow(frame, title, type, flags, workspace)
34 {
35 	InitData();
36 }
37 
38 
39 BDirectWindow::BDirectWindow(BRect frame, const char *title, window_look look,
40 	window_feel feel, uint32 flags, uint32 workspace)
41 	: BWindow(frame, title, look, feel, flags, workspace)
42 {
43 	InitData();
44 }
45 
46 
47 BDirectWindow::~BDirectWindow()
48 {
49 	DisposeData();
50 }
51 
52 
53 // start of regular BWindow API
54 BArchivable *
55 BDirectWindow::Instantiate(BMessage *data)
56 {
57 	return NULL;
58 }
59 
60 
61 status_t
62 BDirectWindow::Archive(BMessage *data, bool deep) const
63 {
64 	return inherited::Archive(data, deep);
65 }
66 
67 
68 void
69 BDirectWindow::Quit()
70 {
71 	inherited::Quit();
72 }
73 
74 
75 void
76 BDirectWindow::DispatchMessage(BMessage *message, BHandler *handler)
77 {
78 	inherited::DispatchMessage(message, handler);
79 }
80 
81 
82 void
83 BDirectWindow::MessageReceived(BMessage *message)
84 {
85 	inherited::MessageReceived(message);
86 }
87 
88 
89 void
90 BDirectWindow::FrameMoved(BPoint new_position)
91 {
92 	inherited::FrameMoved(new_position);
93 }
94 
95 
96 void
97 BDirectWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws)
98 {
99 	inherited::WorkspacesChanged(old_ws, new_ws);
100 }
101 
102 
103 void
104 BDirectWindow::WorkspaceActivated(int32 ws, bool state)
105 {
106 	inherited::WorkspaceActivated(ws, state);
107 }
108 
109 
110 void
111 BDirectWindow::FrameResized(float new_width, float new_height)
112 {
113 	inherited::FrameResized(new_width, new_height);
114 }
115 
116 
117 void
118 BDirectWindow::Minimize(bool minimize)
119 {
120 	inherited::Minimize(minimize);
121 }
122 
123 
124 void
125 BDirectWindow::Zoom(BPoint rec_position, float rec_width, float rec_height)
126 {
127 	inherited::Zoom(rec_position, rec_width, rec_height);
128 }
129 
130 
131 void
132 BDirectWindow::ScreenChanged(BRect screen_size, color_space depth)
133 {
134 	inherited::ScreenChanged(screen_size, depth);
135 }
136 
137 
138 void
139 BDirectWindow::MenusBeginning()
140 {
141 	inherited::MenusBeginning();
142 }
143 
144 
145 void
146 BDirectWindow::MenusEnded()
147 {
148 	inherited::MenusEnded();
149 }
150 
151 
152 void
153 BDirectWindow::WindowActivated(bool state)
154 {
155 	inherited::WindowActivated(state);
156 }
157 
158 
159 void
160 BDirectWindow::Show()
161 {
162 	inherited::Show();
163 }
164 
165 
166 void
167 BDirectWindow::Hide()
168 {
169 	inherited::Hide();
170 }
171 
172 
173 BHandler *
174 BDirectWindow::ResolveSpecifier(BMessage *msg, int32 index,
175 	BMessage *specifier, int32 form, const char *property)
176 {
177 	return inherited::ResolveSpecifier(msg, index, specifier, form, property);
178 }
179 
180 
181 status_t
182 BDirectWindow::GetSupportedSuites(BMessage *data)
183 {
184 	return inherited::GetSupportedSuites(data);
185 }
186 
187 
188 status_t
189 BDirectWindow::Perform(perform_code d, void *arg)
190 {
191 	return inherited::Perform(d, arg);
192 }
193 
194 
195 void
196 BDirectWindow::task_looper()
197 {
198 	inherited::task_looper();
199 }
200 
201 
202 BMessage *
203 BDirectWindow::ConvertToMessage(void *raw, int32 code)
204 {
205 	return inherited::ConvertToMessage(raw, code);
206 }
207 
208 
209 //	#pragma mark - BDirectWindow specific API
210 
211 
212 void
213 BDirectWindow::DirectConnected(direct_buffer_info *info)
214 {
215 	// implemented in subclasses
216 }
217 
218 
219 status_t
220 BDirectWindow::GetClippingRegion(BRegion *region, BPoint *origin) const
221 {
222 	if (region == NULL)
223 		return B_BAD_VALUE;
224 
225 	if (IsLocked() || !LockDirect())
226 		return B_ERROR;
227 
228 	if (fInDirectConnect) {
229 		UnlockDirect();
230 		return B_ERROR;
231 	}
232 
233 	// BPoint's coordinates are floats. We can only work
234 	// with integers._DaemonStarter
235 	int32 originX, originY;
236 	if (origin == NULL) {
237 		originX = 0;
238 		originY = 0;
239 	} else {
240 		originX = (int32)origin->x;
241 		originY = (int32)origin->y;
242 	}
243 
244 #ifndef HAIKU_TARGET_PLATFORM_DANO
245 	// Since we are friend of BRegion, we can access its private members.
246 	// Otherwise, we would need to call BRegion::Include(clipping_rect)
247 	// for every clipping_rect in our clip_list, and that would be much
248 	// more overkill than this (tested ).
249 	region->set_size(fBufferDesc->clip_list_count);
250 	region->count = fBufferDesc->clip_list_count;
251 	region->bound = fBufferDesc->clip_bounds;
252 	for (uint32 c = 0; c < fBufferDesc->clip_list_count; c++)
253 		region->data[c] = fBufferDesc->clip_list[c];
254 
255 	// adjust bounds by the given origin point
256 	region->OffsetBy(-originX, -originY);
257 #endif
258 
259 	UnlockDirect();
260 
261 	return B_OK;
262 
263 }
264 
265 
266 status_t
267 BDirectWindow::SetFullScreen(bool enable)
268 {
269 	if (fIsFullScreen == enable)
270 		return B_OK;
271 
272 	status_t status = B_ERROR;
273 	if (Lock()) {
274 		fLink->StartMessage(AS_DIRECT_WINDOW_SET_FULLSCREEN);
275 		fLink->Attach<bool>(enable);
276 
277 		if (fLink->FlushWithReply(status) == B_OK
278 			&& status == B_OK) {
279 			fIsFullScreen = enable;
280 		}
281 		Unlock();
282 	}
283 	return status;
284 }
285 
286 
287 bool
288 BDirectWindow::IsFullScreen() const
289 {
290 	return fIsFullScreen;
291 }
292 
293 
294 /*static*/
295 bool
296 BDirectWindow::SupportsWindowMode(screen_id id)
297 {
298 /*	display_mode mode;
299 	status_t status = BScreen(id).GetMode(&mode);
300 	if (status == B_OK)
301 		return mode.flags & B_PARALLEL_ACCESS;
302 
303 	return false;*/
304 	// TODO: Apparently, the above is false for the vesa driver,
305 	// but enabling it doesn't do any harm... maybe we should just return always true.
306 	// At least, I can't see why window mode shouldn't be supported.
307 	// additional NOTE: it probably depends on wether hardware cursor is supported or
308 	// not
309 	return true;
310 }
311 
312 
313 //	#pragma mark - Private methods
314 
315 /* static */
316 int32
317 BDirectWindow::_DaemonStarter(void *arg)
318 {
319 	return static_cast<BDirectWindow *>(arg)->DirectDaemonFunc();
320 }
321 
322 
323 int32
324 BDirectWindow::DirectDaemonFunc()
325 {
326 	while (!fDaemonKiller) {
327 		// This sem is released by the app_server when our
328 		// clipping region changes, or when our window is moved,
329 		// resized, etc. etc.
330 		status_t status;
331 		do {
332 			status = acquire_sem(fDisableSem);
333 		} while (status == B_INTERRUPTED);
334 
335 		if (status < B_OK)
336 			return -1;
337 
338 		if (LockDirect()) {
339 			if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START)
340 				fConnectionEnable = true;
341 
342 			fInDirectConnect = true;
343 			DirectConnected(fBufferDesc);
344 			fInDirectConnect = false;
345 
346 			if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
347 				fConnectionEnable = false;
348 
349 			UnlockDirect();
350 		}
351 
352 		// The app_server then waits (with a timeout) on this sem.
353 		// If we aren't quick enough to release this sem, our app
354 		// will be terminated by the app_server
355 		if (release_sem(fDisableSemAck) != B_OK)
356 			return -1;
357 	}
358 
359 	return 0;
360 }
361 
362 
363 // LockDirect() and UnlockDirect() are no-op on R5. I tried to call (R5's) LockDirect()
364 // repeatedly, from the same thread and from different threads, nothing happened.
365 // I implemented them anyway, as they were the first methods I wrote
366 // in this class (As you can see, I even needed to cast away their constness
367 // to make them do something useful).
368 // They're not needed though, as the direct_daemon_thread doesn't change
369 // any shared data. They are probably here for future enhancements (see also the
370 // comment in DriverSetup()
371 bool
372 BDirectWindow::LockDirect() const
373 {
374 	status_t status = B_OK;
375 
376 #if DW_NEEDS_LOCKING
377 	BDirectWindow *casted = const_cast<BDirectWindow *>(this);
378 
379 	if (atomic_add(&casted->fDirectLock, 1) > 0) {
380 		do {
381 			status = acquire_sem(fDirectSem);
382 		} while (status == B_INTERRUPTED);
383 	}
384 
385 	if (status == B_OK) {
386 		casted->fDirectLockOwner = find_thread(NULL);
387 		casted->fDirectLockCount++;
388 	}
389 #endif
390 
391 	return status == B_OK;
392 }
393 
394 
395 void
396 BDirectWindow::UnlockDirect() const
397 {
398 #if DW_NEEDS_LOCKING
399 	BDirectWindow *casted = const_cast<BDirectWindow *>(this);
400 
401 	if (atomic_add(&casted->fDirectLock, -1) > 1)
402 		release_sem(casted->fDirectSem);
403 
404 	casted->fDirectLockCount--;
405 #endif
406 }
407 
408 
409 void
410 BDirectWindow::InitData()
411 {
412 	fConnectionEnable = false;
413 	fIsFullScreen = false;
414 	fInDirectConnect = false;
415 
416 	fInitStatus = 0;
417 
418 	fDirectDriverReady = false;
419 	fDirectDriverType = 0;
420 	fDirectDriverToken = 0;
421 	direct_driver = NULL;
422 
423 	status_t status = B_ERROR;
424 	struct direct_window_sync_data syncData;
425 	if (Lock()) {
426 		fLink->StartMessage(AS_DIRECT_WINDOW_GET_SYNC_DATA);
427 		if (fLink->FlushWithReply(status) == B_OK
428 			&& status == B_OK) {
429 			fLink->Read<direct_window_sync_data>(&syncData);
430 		}
431 		Unlock();
432 	}
433 	if (status < B_OK)
434 		return;
435 
436 #if DW_NEEDS_LOCKING
437 	fDirectLock = 0;
438 	fDirectLockCount = 0;
439 	fDirectLockOwner = -1;
440 	fDirectLockStack = NULL;
441 	fDirectSem = create_sem(1, "direct sem");
442 	if (fDirectSem > 0)
443 		fInitStatus |= DW_STATUS_SEM_CREATED;
444 #endif
445 
446 	fSourceClippingArea = syncData.area;
447 	fDisableSem = syncData.disable_sem;
448 	fDisableSemAck = syncData.disable_sem_ack;
449 
450 	fClonedClippingArea = clone_area("Clone direct area", (void**)&fBufferDesc,
451 		B_ANY_ADDRESS, B_READ_AREA, fSourceClippingArea);
452 
453 	if (fClonedClippingArea > 0) {
454 		fInitStatus |= DW_STATUS_AREA_CLONED;
455 
456 		fDirectDaemonId = spawn_thread(_DaemonStarter, "direct daemon",
457 				B_DISPLAY_PRIORITY, this);
458 
459 		if (fDirectDaemonId > 0) {
460 			fDaemonKiller = false;
461 			if (resume_thread(fDirectDaemonId) == B_OK)
462 				fInitStatus |= DW_STATUS_THREAD_STARTED;
463 			else
464 				kill_thread(fDirectDaemonId);
465 		}
466 	}
467 }
468 
469 
470 void
471 BDirectWindow::DisposeData()
472 {
473 	// wait until the connection terminates: we can't destroy
474 	// the object until the client receives the B_DIRECT_STOP
475 	// notification, or bad things will happen
476 	while (fConnectionEnable)
477 		snooze(50000);
478 
479 	LockDirect();
480 
481 	if (fInitStatus & DW_STATUS_THREAD_STARTED) {
482 		fDaemonKiller = true;
483 		// Release this sem, otherwise the Direct daemon thread
484 		// will wait forever on it
485 		release_sem(fDisableSem);
486 		status_t retVal;
487 		wait_for_thread(fDirectDaemonId, &retVal);
488 	}
489 
490 #if DW_NEEDS_LOCKING
491 	if (fInitStatus & DW_STATUS_SEM_CREATED)
492 		delete_sem(fDirectSem);
493 #endif
494 
495 	if (fInitStatus & DW_STATUS_AREA_CLONED)
496 		delete_area(fClonedClippingArea);
497 }
498 
499 
500 status_t
501 BDirectWindow::DriverSetup() const
502 {
503 	// Unimplemented in R5.
504 	// This function is probably here because they wanted, in a future time,
505 	// to implement graphic acceleration within BDirectWindow
506 	// (in fact, there is also a BDirectDriver member in BDirectWindow,
507 	// though it's not used).
508 
509 	return B_OK;
510 }
511 
512 
513 void BDirectWindow::_ReservedDirectWindow1() {}
514 void BDirectWindow::_ReservedDirectWindow2() {}
515 void BDirectWindow::_ReservedDirectWindow3() {}
516 void BDirectWindow::_ReservedDirectWindow4() {}
517