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