xref: /haiku/src/kits/game/DirectWindow.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 /*
2  * Copyright 2003-2005, 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 		Unlock();
281 	}
282 	return status;
283 }
284 
285 
286 bool
287 BDirectWindow::IsFullScreen() const
288 {
289 	return fIsFullScreen;
290 }
291 
292 
293 /*static*/
294 bool
295 BDirectWindow::SupportsWindowMode(screen_id id)
296 {
297 /*	display_mode mode;
298 	status_t status = BScreen(id).GetMode(&mode);
299 	if (status == B_OK)
300 		return mode.flags & B_PARALLEL_ACCESS;
301 
302 	return false;*/
303 	// TODO: Apparently, the above is false for the vesa driver,
304 	// but enabling it doesn't do any harm... maybe we should just return always true.
305 	// At least, I can't see why window mode shouldn't be supported.
306 	return true;
307 }
308 
309 
310 //	#pragma mark - Private methods
311 
312 /* static */
313 int32
314 BDirectWindow::_DaemonStarter(void *arg)
315 {
316 	return static_cast<BDirectWindow *>(arg)->DirectDaemonFunc();
317 }
318 
319 
320 int32
321 BDirectWindow::DirectDaemonFunc()
322 {
323 	while (!fDaemonKiller) {
324 		// This sem is released by the app_server when our
325 		// clipping region changes, or when our window is moved,
326 		// resized, etc. etc.
327 		status_t status;
328 		do {
329 			status = acquire_sem(fDisableSem);
330 		} while (status == B_INTERRUPTED);
331 
332 		if (status < B_OK)
333 			return -1;
334 
335 		if (LockDirect()) {
336 			if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START)
337 				fConnectionEnable = true;
338 
339 			fInDirectConnect = true;
340 			DirectConnected(fBufferDesc);
341 			fInDirectConnect = false;
342 
343 			if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
344 				fConnectionEnable = false;
345 
346 			UnlockDirect();
347 		}
348 
349 		// The app_server then waits (with a timeout) on this sem.
350 		// If we aren't quick enough to release this sem, our app
351 		// will be terminated by the app_server
352 		if (release_sem(fDisableSemAck) != B_OK)
353 			return -1;
354 	}
355 
356 	return 0;
357 }
358 
359 
360 // LockDirect() and UnlockDirect() are no-op on R5. I tried to call (R5's) LockDirect()
361 // repeatedly, from the same thread and from different threads, nothing happened.
362 // I implemented them anyway, as they were the first methods I wrote
363 // in this class (As you can see, I even needed to cast away their constness
364 // to make them do something useful).
365 // They're not needed though, as the direct_daemon_thread doesn't change
366 // any shared data. They are probably here for future enhancements (see also the
367 // comment in DriverSetup()
368 bool
369 BDirectWindow::LockDirect() const
370 {
371 	status_t status = B_OK;
372 
373 #if DW_NEEDS_LOCKING
374 	BDirectWindow *casted = const_cast<BDirectWindow *>(this);
375 
376 	if (atomic_add(&casted->fDirectLock, 1) > 0) {
377 		do {
378 			status = acquire_sem(fDirectSem);
379 		} while (status == B_INTERRUPTED);
380 	}
381 
382 	if (status == B_OK) {
383 		casted->fDirectLockOwner = find_thread(NULL);
384 		casted->fDirectLockCount++;
385 	}
386 #endif
387 
388 	return status == B_OK;
389 }
390 
391 
392 void
393 BDirectWindow::UnlockDirect() const
394 {
395 #if DW_NEEDS_LOCKING
396 	BDirectWindow *casted = const_cast<BDirectWindow *>(this);
397 
398 	if (atomic_add(&casted->fDirectLock, -1) > 1)
399 		release_sem(casted->fDirectSem);
400 
401 	casted->fDirectLockCount--;
402 #endif
403 }
404 
405 
406 void
407 BDirectWindow::InitData()
408 {
409 	fConnectionEnable = false;
410 	fIsFullScreen = false;
411 	fInDirectConnect = false;
412 
413 	fInitStatus = 0;
414 
415 	fDirectDriverReady = false;
416 	fDirectDriverType = 0;
417 	fDirectDriverToken = 0;
418 	direct_driver = NULL;
419 
420 	status_t status = B_ERROR;
421 	struct direct_window_sync_data syncData;
422 	if (Lock()) {
423 		fLink->StartMessage(AS_DIRECT_WINDOW_GET_SYNC_DATA);
424 		if (fLink->FlushWithReply(status) == B_OK
425 			&& status == B_OK) {
426 			fLink->Read<direct_window_sync_data>(&syncData);
427 		}
428 		Unlock();
429 	}
430 	if (status < B_OK)
431 		return;
432 
433 #if DW_NEEDS_LOCKING
434 	fDirectLock = 0;
435 	fDirectLockCount = 0;
436 	fDirectLockOwner = -1;
437 	fDirectLockStack = NULL;
438 	fDirectSem = create_sem(1, "direct sem");
439 	if (fDirectSem > 0)
440 		fInitStatus |= DW_STATUS_SEM_CREATED;
441 #endif
442 
443 	fSourceClippingArea = syncData.area;
444 	fDisableSem = syncData.disable_sem;
445 	fDisableSemAck = syncData.disable_sem_ack;
446 
447 	fClonedClippingArea = clone_area("Clone direct area", (void**)&fBufferDesc,
448 		B_ANY_ADDRESS, B_READ_AREA, fSourceClippingArea);
449 
450 	if (fSourceClippingArea > 0) {
451 		fInitStatus |= DW_STATUS_AREA_CLONED;
452 
453 		fDirectDaemonId = spawn_thread(_DaemonStarter, "direct daemon",
454 				B_DISPLAY_PRIORITY, this);
455 
456 		if (fDirectDaemonId > 0) {
457 			fDaemonKiller = false;
458 			if (resume_thread(fDirectDaemonId) == B_OK)
459 				fInitStatus |= DW_STATUS_THREAD_STARTED;
460 			else
461 				kill_thread(fDirectDaemonId);
462 		}
463 	}
464 }
465 
466 
467 void
468 BDirectWindow::DisposeData()
469 {
470 	// wait until the connection terminates: we can't destroy
471 	// the object until the client receives the B_DIRECT_STOP
472 	// notification, or bad things will happen
473 	while (fConnectionEnable)
474 		snooze(50000);
475 
476 	LockDirect();
477 
478 	if (fInitStatus & DW_STATUS_THREAD_STARTED) {
479 		fDaemonKiller = true;
480 		// Release this sem, otherwise the Direct daemon thread
481 		// will wait forever on it
482 		release_sem(fDisableSem);
483 		status_t retVal;
484 		wait_for_thread(fDirectDaemonId, &retVal);
485 	}
486 
487 #if DW_NEEDS_LOCKING
488 	if (fInitStatus & DW_STATUS_SEM_CREATED)
489 		delete_sem(fDirectSem);
490 #endif
491 
492 	if (fInitStatus & DW_STATUS_AREA_CLONED)
493 		delete_area(fClonedClippingArea);
494 }
495 
496 
497 status_t
498 BDirectWindow::DriverSetup() const
499 {
500 	// Unimplemented in R5.
501 	// This function is probably here because they wanted, in a future time,
502 	// to implement graphic acceleration within BDirectWindow
503 	// (in fact, there is also a BDirectDriver member in BDirectWindow,
504 	// though it's not used).
505 
506 	return B_OK;
507 }
508 
509 
510 void BDirectWindow::_ReservedDirectWindow1() {}
511 void BDirectWindow::_ReservedDirectWindow2() {}
512 void BDirectWindow::_ReservedDirectWindow3() {}
513 void BDirectWindow::_ReservedDirectWindow4() {}
514