2 * Copyright 2003-2009 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stefano Ceccherini <stefano.ceccherini@gmail.com>
7 * Carwyn Jones <turok2@currantbun.com>
11 #include <DirectWindow.h>
19 #include <AppServerLink.h>
20 #include <DirectWindowPrivate.h>
21 #include <ServerProtocol.h>
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
34 DW_STATUS_AREA_CLONED
= 0x1,
35 DW_STATUS_THREAD_STARTED
= 0x2,
36 DW_STATUS_SEM_CREATED
= 0x4
44 print_direct_buffer_state(const direct_buffer_state
&state
)
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
);
69 print_direct_driver_state(const direct_driver_state
&state
)
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
);
88 print_direct_buffer_layout(const buffer_layout
&layout
)
91 if (layout
== B_BUFFER_NONINTERLEAVED
)
92 strcpy(string
, "B_BUFFER_NONINTERLEAVED");
94 strcpy(string
, "unknown");
96 OUTPUT("layout: %s\n", string
);
101 print_direct_buffer_orientation(const buffer_orientation
&orientation
)
104 switch (orientation
) {
105 case B_BUFFER_TOP_TO_BOTTOM
:
106 strcpy(string
, "B_BUFFER_TOP_TO_BOTTOM");
108 case B_BUFFER_BOTTOM_TO_TOP
:
109 strcpy(string
, "B_BUFFER_BOTTOM_TO_TOP");
112 strcpy(string
, "unknown");
116 OUTPUT("orientation: %s\n", string
);
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
);
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
);
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");
145 region
.Set(info
.window_bounds
);
146 region
.PrintToStream();
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();
167 BDirectWindow::BDirectWindow(BRect frame
, const char* title
, window_type type
,
168 uint32 flags
, uint32 workspace
)
170 BWindow(frame
, title
, type
, flags
, workspace
)
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
)
185 BDirectWindow::~BDirectWindow()
191 // #pragma mark - BWindow API implementation
195 BDirectWindow::Instantiate(BMessage
* data
)
202 BDirectWindow::Archive(BMessage
* data
, bool deep
) const
204 return inherited::Archive(data
, deep
);
209 BDirectWindow::Quit()
216 BDirectWindow::DispatchMessage(BMessage
* message
, BHandler
* handler
)
218 inherited::DispatchMessage(message
, handler
);
223 BDirectWindow::MessageReceived(BMessage
* message
)
225 inherited::MessageReceived(message
);
230 BDirectWindow::FrameMoved(BPoint newPosition
)
232 inherited::FrameMoved(newPosition
);
237 BDirectWindow::WorkspacesChanged(uint32 oldWorkspaces
, uint32 newWorkspaces
)
239 inherited::WorkspacesChanged(oldWorkspaces
, newWorkspaces
);
244 BDirectWindow::WorkspaceActivated(int32 index
, bool state
)
246 inherited::WorkspaceActivated(index
, state
);
251 BDirectWindow::FrameResized(float newWidth
, float newHeight
)
253 inherited::FrameResized(newWidth
, newHeight
);
258 BDirectWindow::Minimize(bool minimize
)
260 inherited::Minimize(minimize
);
265 BDirectWindow::Zoom(BPoint recPosition
, float recWidth
, float recHeight
)
267 inherited::Zoom(recPosition
, recWidth
, recHeight
);
272 BDirectWindow::ScreenChanged(BRect screenFrame
, color_space depth
)
274 inherited::ScreenChanged(screenFrame
, depth
);
279 BDirectWindow::MenusBeginning()
281 inherited::MenusBeginning();
286 BDirectWindow::MenusEnded()
288 inherited::MenusEnded();
293 BDirectWindow::WindowActivated(bool state
)
295 inherited::WindowActivated(state
);
300 BDirectWindow::Show()
307 BDirectWindow::Hide()
314 BDirectWindow::ResolveSpecifier(BMessage
* message
, int32 index
,
315 BMessage
* specifier
, int32 what
, const char* property
)
317 return inherited::ResolveSpecifier(message
, index
, specifier
, what
,
323 BDirectWindow::GetSupportedSuites(BMessage
* data
)
325 return inherited::GetSupportedSuites(data
);
330 BDirectWindow::Perform(perform_code d
, void* arg
)
332 return inherited::Perform(d
, arg
);
337 BDirectWindow::task_looper()
339 inherited::task_looper();
344 BDirectWindow::ConvertToMessage(void* raw
, int32 code
)
346 return inherited::ConvertToMessage(raw
, code
);
350 // #pragma mark - BDirectWindow specific API
354 BDirectWindow::DirectConnected(direct_buffer_info
* info
)
356 // implemented in subclasses
361 BDirectWindow::GetClippingRegion(BRegion
* region
, BPoint
* origin
) const
366 if (IsLocked() || !_LockDirect())
369 if (!fInDirectConnect
) {
374 // BPoint's coordinates are floats. We can only work
375 // with integers._DaemonStarter
376 int32 originX
, originY
;
377 if (origin
== NULL
) {
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
)) {
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
);
413 BDirectWindow::SetFullScreen(bool enable
)
415 if (fIsFullScreen
== enable
)
418 status_t status
= B_ERROR
;
420 fLink
->StartMessage(AS_DIRECT_WINDOW_SET_FULLSCREEN
);
421 fLink
->Attach
<bool>(enable
);
423 if (fLink
->FlushWithReply(status
) == B_OK
425 fIsFullScreen
= enable
;
434 BDirectWindow::IsFullScreen() const
436 return fIsFullScreen
;
441 BDirectWindow::SupportsWindowMode(screen_id id
)
444 status_t status
= BScreen(id
).GetMode(&mode
);
446 return (mode
.flags
& B_PARALLEL_ACCESS
) != 0;
452 // #pragma mark - Private methods
456 BDirectWindow::_daemon_thread(void* arg
)
458 return static_cast<BDirectWindow
*>(arg
)->_DirectDaemon();
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.
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));
481 print_direct_buffer_info(*fBufferDesc
);
485 if ((fBufferDesc
->buffer_state
& B_DIRECT_MODE_MASK
)
487 fConnectionEnable
= true;
489 fInDirectConnect
= true;
490 DirectConnected(fBufferDesc
);
491 fInDirectConnect
= false;
493 if ((fBufferDesc
->buffer_state
& B_DIRECT_MODE_MASK
)
495 fConnectionEnable
= false;
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",
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,
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
;
525 BDirectWindow
* casted
= const_cast<BDirectWindow
*>(this);
527 if (atomic_add(&casted
->fDirectLock
, 1) > 0) {
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
++;
539 return status
== B_OK
;
544 BDirectWindow::_UnlockDirect() const
547 BDirectWindow
* casted
= const_cast<BDirectWindow
*>(this);
549 if (atomic_add(&casted
->fDirectLock
, -1) > 1)
550 release_sem(casted
->fDirectSem
);
552 casted
->fDirectLockCount
--;
558 BDirectWindow::_InitData()
560 fConnectionEnable
= false;
561 fIsFullScreen
= false;
562 fInDirectConnect
= false;
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
);
578 fDirectLockCount
= 0;
579 fDirectLockOwner
= -1;
580 fDirectLockStack
= NULL
;
581 fDirectSem
= create_sem(0, "direct sem");
583 fInitStatus
|= DW_STATUS_SEM_CREATED
;
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
;
604 kill_thread(fDirectDaemonId
);
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
)
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
);
627 wait_for_thread(fDirectDaemonId
, &retVal
);
631 if (fInitStatus
& DW_STATUS_SEM_CREATED
)
632 delete_sem(fDirectSem
);
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() {}