tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / game / DirectWindow.cpp
blob262bfb4cd3ced23d2eda09b1d38577af256e4bb4
1 /*
2 * Copyright 2003-2009 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stefano Ceccherini <stefano.ceccherini@gmail.com>
7 * Carwyn Jones <turok2@currantbun.com>
8 */
11 #include <DirectWindow.h>
13 #include <stdio.h>
14 #include <string.h>
16 #include <Screen.h>
18 #include <clipping.h>
19 #include <AppServerLink.h>
20 #include <DirectWindowPrivate.h>
21 #include <ServerProtocol.h>
24 //#define DEBUG 1
25 #define OUTPUT printf
26 //#define OUTPUT debug_printf
29 // We don't need this kind of locking, since the directDaemonFunc
30 // doesn't access critical shared data.
31 #define DW_NEEDS_LOCKING 0
33 enum dw_status_bits {
34 DW_STATUS_AREA_CLONED = 0x1,
35 DW_STATUS_THREAD_STARTED = 0x2,
36 DW_STATUS_SEM_CREATED = 0x4
40 #if DEBUG
43 static void
44 print_direct_buffer_state(const direct_buffer_state &state)
46 char string[128];
47 int modeState = state & B_DIRECT_MODE_MASK;
48 if (modeState == B_DIRECT_START)
49 strcpy(string, "B_DIRECT_START");
50 else if (modeState == B_DIRECT_MODIFY)
51 strcpy(string, "B_DIRECT_MODIFY");
52 else if (modeState == B_DIRECT_STOP)
53 strcpy(string, "B_DIRECT_STOP");
55 if (state & B_CLIPPING_MODIFIED)
56 strcat(string, " | B_CLIPPING_MODIFIED");
57 if (state & B_BUFFER_RESIZED)
58 strcat(string, " | B_BUFFER_RESIZED");
59 if (state & B_BUFFER_MOVED)
60 strcat(string, " | B_BUFFER_MOVED");
61 if (state & B_BUFFER_RESET)
62 strcat(string, " | B_BUFFER_RESET");
64 OUTPUT("direct_buffer_state: %s\n", string);
68 static void
69 print_direct_driver_state(const direct_driver_state &state)
71 if (state == 0)
72 return;
74 char string[64];
75 if (state == B_DRIVER_CHANGED)
76 strcpy(string, "B_DRIVER_CHANGED");
77 else if (state == B_MODE_CHANGED)
78 strcpy(string, "B_MODE_CHANGED");
80 OUTPUT("direct_driver_state: %s\n", string);
84 #if DEBUG > 1
87 static void
88 print_direct_buffer_layout(const buffer_layout &layout)
90 char string[64];
91 if (layout == B_BUFFER_NONINTERLEAVED)
92 strcpy(string, "B_BUFFER_NONINTERLEAVED");
93 else
94 strcpy(string, "unknown");
96 OUTPUT("layout: %s\n", string);
100 static void
101 print_direct_buffer_orientation(const buffer_orientation &orientation)
103 char string[64];
104 switch (orientation) {
105 case B_BUFFER_TOP_TO_BOTTOM:
106 strcpy(string, "B_BUFFER_TOP_TO_BOTTOM");
107 break;
108 case B_BUFFER_BOTTOM_TO_TOP:
109 strcpy(string, "B_BUFFER_BOTTOM_TO_TOP");
110 break;
111 default:
112 strcpy(string, "unknown");
113 break;
116 OUTPUT("orientation: %s\n", string);
120 #endif // DEBUG > 2
123 static void
124 print_direct_buffer_info(const direct_buffer_info &info)
126 print_direct_buffer_state(info.buffer_state);
127 print_direct_driver_state(info.driver_state);
129 # if DEBUG > 1
130 OUTPUT("bits: %p\n", info.bits);
131 OUTPUT("pci_bits: %p\n", info.pci_bits);
132 OUTPUT("bytes_per_row: %ld\n", info.bytes_per_row);
133 OUTPUT("bits_per_pixel: %lu\n", info.bits_per_pixel);
134 OUTPUT("pixel_format: %d\n", info.pixel_format);
135 print_direct_buffer_layout(info.layout);
136 print_direct_buffer_orientation(info.orientation);
138 # if DEBUG > 2
139 // TODO: this won't work correctly with debug_printf()
140 printf("CLIPPING INFO:\n");
141 printf("clipping_rects count: %ld\n", info.clip_list_count);
143 printf("- window_bounds:\n");
144 BRegion region;
145 region.Set(info.window_bounds);
146 region.PrintToStream();
148 region.MakeEmpty();
149 for (uint32 i = 0; i < info.clip_list_count; i++)
150 region.Include(info.clip_list[i]);
152 printf("- clip_list:\n");
153 region.PrintToStream();
154 # endif
155 # endif
157 OUTPUT("\n");
161 #endif // DEBUG
164 // #pragma mark -
167 BDirectWindow::BDirectWindow(BRect frame, const char* title, window_type type,
168 uint32 flags, uint32 workspace)
170 BWindow(frame, title, type, flags, workspace)
172 _InitData();
176 BDirectWindow::BDirectWindow(BRect frame, const char* title, window_look look,
177 window_feel feel, uint32 flags, uint32 workspace)
179 BWindow(frame, title, look, feel, flags, workspace)
181 _InitData();
185 BDirectWindow::~BDirectWindow()
187 _DisposeData();
191 // #pragma mark - BWindow API implementation
194 BArchivable*
195 BDirectWindow::Instantiate(BMessage* data)
197 return NULL;
201 status_t
202 BDirectWindow::Archive(BMessage* data, bool deep) const
204 return inherited::Archive(data, deep);
208 void
209 BDirectWindow::Quit()
211 inherited::Quit();
215 void
216 BDirectWindow::DispatchMessage(BMessage* message, BHandler* handler)
218 inherited::DispatchMessage(message, handler);
222 void
223 BDirectWindow::MessageReceived(BMessage* message)
225 inherited::MessageReceived(message);
229 void
230 BDirectWindow::FrameMoved(BPoint newPosition)
232 inherited::FrameMoved(newPosition);
236 void
237 BDirectWindow::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
239 inherited::WorkspacesChanged(oldWorkspaces, newWorkspaces);
243 void
244 BDirectWindow::WorkspaceActivated(int32 index, bool state)
246 inherited::WorkspaceActivated(index, state);
250 void
251 BDirectWindow::FrameResized(float newWidth, float newHeight)
253 inherited::FrameResized(newWidth, newHeight);
257 void
258 BDirectWindow::Minimize(bool minimize)
260 inherited::Minimize(minimize);
264 void
265 BDirectWindow::Zoom(BPoint recPosition, float recWidth, float recHeight)
267 inherited::Zoom(recPosition, recWidth, recHeight);
271 void
272 BDirectWindow::ScreenChanged(BRect screenFrame, color_space depth)
274 inherited::ScreenChanged(screenFrame, depth);
278 void
279 BDirectWindow::MenusBeginning()
281 inherited::MenusBeginning();
285 void
286 BDirectWindow::MenusEnded()
288 inherited::MenusEnded();
292 void
293 BDirectWindow::WindowActivated(bool state)
295 inherited::WindowActivated(state);
299 void
300 BDirectWindow::Show()
302 inherited::Show();
306 void
307 BDirectWindow::Hide()
309 inherited::Hide();
313 BHandler*
314 BDirectWindow::ResolveSpecifier(BMessage* message, int32 index,
315 BMessage* specifier, int32 what, const char* property)
317 return inherited::ResolveSpecifier(message, index, specifier, what,
318 property);
322 status_t
323 BDirectWindow::GetSupportedSuites(BMessage* data)
325 return inherited::GetSupportedSuites(data);
329 status_t
330 BDirectWindow::Perform(perform_code d, void* arg)
332 return inherited::Perform(d, arg);
336 void
337 BDirectWindow::task_looper()
339 inherited::task_looper();
343 BMessage*
344 BDirectWindow::ConvertToMessage(void* raw, int32 code)
346 return inherited::ConvertToMessage(raw, code);
350 // #pragma mark - BDirectWindow specific API
353 void
354 BDirectWindow::DirectConnected(direct_buffer_info* info)
356 // implemented in subclasses
360 status_t
361 BDirectWindow::GetClippingRegion(BRegion* region, BPoint* origin) const
363 if (region == NULL)
364 return B_BAD_VALUE;
366 if (IsLocked() || !_LockDirect())
367 return B_ERROR;
369 if (!fInDirectConnect) {
370 _UnlockDirect();
371 return B_ERROR;
374 // BPoint's coordinates are floats. We can only work
375 // with integers._DaemonStarter
376 int32 originX, originY;
377 if (origin == NULL) {
378 originX = 0;
379 originY = 0;
380 } else {
381 originX = (int32)origin->x;
382 originY = (int32)origin->y;
385 #ifndef HAIKU_TARGET_PLATFORM_DANO
386 // Since we are friend of BRegion, we can access its private members.
387 // Otherwise, we would need to call BRegion::Include(clipping_rect)
388 // for every clipping_rect in our clip_list, and that would be much
389 // more overkill than this (tested ).
390 if (!region->_SetSize(fBufferDesc->clip_list_count)) {
391 _UnlockDirect();
392 return B_NO_MEMORY;
394 region->fCount = fBufferDesc->clip_list_count;
395 region->fBounds = region->_ConvertToInternal(fBufferDesc->clip_bounds);
396 for (uint32 c = 0; c < fBufferDesc->clip_list_count; c++) {
397 region->fData[c] = region->_ConvertToInternal(
398 fBufferDesc->clip_list[c]);
401 // adjust bounds by the given origin point
402 region->OffsetBy(-originX, -originY);
403 #endif
405 _UnlockDirect();
407 return B_OK;
412 status_t
413 BDirectWindow::SetFullScreen(bool enable)
415 if (fIsFullScreen == enable)
416 return B_OK;
418 status_t status = B_ERROR;
419 if (Lock()) {
420 fLink->StartMessage(AS_DIRECT_WINDOW_SET_FULLSCREEN);
421 fLink->Attach<bool>(enable);
423 if (fLink->FlushWithReply(status) == B_OK
424 && status == B_OK) {
425 fIsFullScreen = enable;
427 Unlock();
429 return status;
433 bool
434 BDirectWindow::IsFullScreen() const
436 return fIsFullScreen;
440 /*static*/ bool
441 BDirectWindow::SupportsWindowMode(screen_id id)
443 display_mode mode;
444 status_t status = BScreen(id).GetMode(&mode);
445 if (status == B_OK)
446 return (mode.flags & B_PARALLEL_ACCESS) != 0;
448 return false;
452 // #pragma mark - Private methods
455 /*static*/ int32
456 BDirectWindow::_daemon_thread(void* arg)
458 return static_cast<BDirectWindow*>(arg)->_DirectDaemon();
462 int32
463 BDirectWindow::_DirectDaemon()
465 while (!fDaemonKiller) {
466 // This sem is released by the app_server when our
467 // clipping region changes, or when our window is moved,
468 // resized, etc. etc.
469 status_t status;
470 do {
471 status = acquire_sem(fDisableSem);
472 } while (status == B_INTERRUPTED);
474 if (status != B_OK) {
475 //fprintf(stderr, "DirectDaemon: failed to acquire direct sem: %s\n",
476 // strerror(status));
477 return -1;
480 #if DEBUG
481 print_direct_buffer_info(*fBufferDesc);
482 #endif
484 if (_LockDirect()) {
485 if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK)
486 == B_DIRECT_START)
487 fConnectionEnable = true;
489 fInDirectConnect = true;
490 DirectConnected(fBufferDesc);
491 fInDirectConnect = false;
493 if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK)
494 == B_DIRECT_STOP)
495 fConnectionEnable = false;
497 _UnlockDirect();
500 // The app_server then waits (with a timeout) on this sem.
501 // If we aren't quick enough to release this sem, our app
502 // will be terminated by the app_server
503 if ((status = release_sem(fDisableSemAck)) != B_OK) {
504 //fprintf(stderr, "DirectDaemon: failed to release sem: %s\n",
505 //strerror(status));
506 return -1;
510 return 0;
514 bool
515 BDirectWindow::_LockDirect() const
517 // LockDirect() and UnlockDirect() are no-op on BeOS. I tried to call BeOS's
518 // version repeatedly, from the same thread and from different threads,
519 // nothing happened.
520 // They're not needed though, as the direct_daemon_thread doesn't change
521 // any shared data. They are probably here for future enhancements.
522 status_t status = B_OK;
524 #if DW_NEEDS_LOCKING
525 BDirectWindow* casted = const_cast<BDirectWindow*>(this);
527 if (atomic_add(&casted->fDirectLock, 1) > 0) {
528 do {
529 status = acquire_sem(casted->fDirectSem);
530 } while (status == B_INTERRUPTED);
533 if (status == B_OK) {
534 casted->fDirectLockOwner = find_thread(NULL);
535 casted->fDirectLockCount++;
537 #endif
539 return status == B_OK;
543 void
544 BDirectWindow::_UnlockDirect() const
546 #if DW_NEEDS_LOCKING
547 BDirectWindow* casted = const_cast<BDirectWindow*>(this);
549 if (atomic_add(&casted->fDirectLock, -1) > 1)
550 release_sem(casted->fDirectSem);
552 casted->fDirectLockCount--;
553 #endif
557 void
558 BDirectWindow::_InitData()
560 fConnectionEnable = false;
561 fIsFullScreen = false;
562 fInDirectConnect = false;
564 fInitStatus = 0;
566 status_t status = B_ERROR;
567 struct direct_window_sync_data syncData;
569 fLink->StartMessage(AS_DIRECT_WINDOW_GET_SYNC_DATA);
570 if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
571 fLink->Read<direct_window_sync_data>(&syncData);
573 if (status != B_OK)
574 return;
576 #if DW_NEEDS_LOCKING
577 fDirectLock = 0;
578 fDirectLockCount = 0;
579 fDirectLockOwner = -1;
580 fDirectLockStack = NULL;
581 fDirectSem = create_sem(0, "direct sem");
582 if (fDirectSem > 0)
583 fInitStatus |= DW_STATUS_SEM_CREATED;
584 #endif
586 fSourceClippingArea = syncData.area;
587 fDisableSem = syncData.disable_sem;
588 fDisableSemAck = syncData.disable_sem_ack;
590 fClonedClippingArea = clone_area("cloned direct area", (void**)&fBufferDesc,
591 B_ANY_ADDRESS, B_READ_AREA, fSourceClippingArea);
593 if (fClonedClippingArea > 0) {
594 fInitStatus |= DW_STATUS_AREA_CLONED;
596 fDirectDaemonId = spawn_thread(_daemon_thread, "direct daemon",
597 B_DISPLAY_PRIORITY, this);
599 if (fDirectDaemonId > 0) {
600 fDaemonKiller = false;
601 if (resume_thread(fDirectDaemonId) == B_OK)
602 fInitStatus |= DW_STATUS_THREAD_STARTED;
603 else
604 kill_thread(fDirectDaemonId);
610 void
611 BDirectWindow::_DisposeData()
613 // wait until the connection terminates: we can't destroy
614 // the object until the client receives the B_DIRECT_STOP
615 // notification, or bad things will happen
616 while (fConnectionEnable)
617 snooze(50000);
619 _LockDirect();
621 if (fInitStatus & DW_STATUS_THREAD_STARTED) {
622 fDaemonKiller = true;
623 // delete this sem, otherwise the Direct daemon thread
624 // will wait forever on it
625 delete_sem(fDisableSem);
626 status_t retVal;
627 wait_for_thread(fDirectDaemonId, &retVal);
630 #if DW_NEEDS_LOCKING
631 if (fInitStatus & DW_STATUS_SEM_CREATED)
632 delete_sem(fDirectSem);
633 #endif
635 if (fInitStatus & DW_STATUS_AREA_CLONED)
636 delete_area(fClonedClippingArea);
640 void BDirectWindow::_ReservedDirectWindow1() {}
641 void BDirectWindow::_ReservedDirectWindow2() {}
642 void BDirectWindow::_ReservedDirectWindow3() {}
643 void BDirectWindow::_ReservedDirectWindow4() {}