2 * Copyright 2002-2009, Haiku Inc.
3 * Distributed under the terms of the MIT License.
6 * Stefano Ceccherini (burton666@libero.it)
7 * Axel Dörfler, axeld@pinc-software.de
11 /*! BPrivateScreen is the class which does the real work for
12 the proxy class BScreen (it interacts with the app_server).
16 #include <PrivateScreen.h>
22 #include <Application.h>
26 #include <ObjectList.h>
29 #include <AutoLocker.h>
32 #include <AppServerLink.h>
33 #include <ServerProtocol.h>
36 using namespace BPrivate
;
42 BObjectList
<BPrivateScreen
> list
;
61 static Screens
* Default()
63 if (sDefaultInstance
== NULL
)
64 pthread_once(&sDefaultInitOnce
, &_InitSingleton
);
66 return sDefaultInstance
;
70 static void _InitSingleton()
72 sDefaultInstance
= new Screens
;
78 static pthread_once_t sDefaultInitOnce
;
79 static Screens
* sDefaultInstance
;
82 pthread_once_t
Screens::sDefaultInitOnce
= PTHREAD_ONCE_INIT
;
83 Screens
* Screens::sDefaultInstance
= NULL
;
85 } // unnamed namespace
89 BPrivateScreen::Get(BWindow
* window
)
91 int32 id
= B_MAIN_SCREEN_ID
.id
;
94 BPrivate::AppServerLink link
;
95 link
.StartMessage(AS_GET_SCREEN_ID_FROM_WINDOW
);
96 link
.Attach
<int32
>(_get_object_token_(window
));
99 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
)
100 link
.Read
<int32
>(&id
);
103 return _Get(id
, false);
108 BPrivateScreen::Get(int32 id
)
110 return _Get(id
, true);
115 BPrivateScreen::_Get(int32 id
, bool check
)
117 // Nothing works without an app_server connection
121 Screens
* screens
= Screens::Default();
122 AutoLocker
<Screens
> locker(screens
);
124 // search for the screen ID
126 for (int32 i
= screens
->list
.CountItems(); i
-- > 0;) {
127 BPrivateScreen
* screen
= screens
->list
.ItemAt(i
);
129 if (screen
->ID() == id
) {
136 // check if ID is valid
141 // we need to allocate a new one
143 BPrivateScreen
* screen
= new (std::nothrow
) BPrivateScreen(id
);
147 screens
->list
.AddItem(screen
);
153 BPrivateScreen::Put(BPrivateScreen
* screen
)
158 Screens
* screens
= Screens::Default();
159 AutoLocker
<Screens
> locker(screens
);
161 if (screen
->_Release()) {
162 if (screen
->ID() != B_MAIN_SCREEN_ID
.id
) {
163 // we always keep the main screen object around - it will
164 // never go away, even if you disconnect all monitors.
165 screens
->list
.RemoveItem(screen
);
172 BPrivateScreen::GetNext(BPrivateScreen
* screen
)
174 Screens
* screens
= Screens::Default();
175 AutoLocker
<Screens
> locker(screens
);
178 status_t status
= screen
->GetNextID(id
);
182 BPrivateScreen
* nextScreen
= Get(id
);
183 if (nextScreen
== NULL
)
192 BPrivateScreen::_IsValid(int32 id
)
194 BPrivate::AppServerLink link
;
195 link
.StartMessage(AS_VALID_SCREEN_ID
);
196 link
.Attach
<int32
>(id
);
199 if (link
.FlushWithReply(status
) != B_OK
|| status
< B_OK
)
210 BPrivateScreen::ColorSpace()
213 if (GetMode(B_CURRENT_WORKSPACE_INDEX
, &mode
) == B_OK
)
214 return (color_space
)mode
.space
;
216 return B_NO_COLOR_SPACE
;
221 BPrivateScreen::Frame()
223 if (system_time() > fLastUpdate
+ 10000) {
224 // invalidate the settings after 10 msecs
225 BPrivate::AppServerLink link
;
226 link
.StartMessage(AS_GET_SCREEN_FRAME
);
227 link
.Attach
<int32
>(ID());
228 link
.Attach
<uint32
>(B_CURRENT_WORKSPACE_INDEX
);
230 status_t status
= B_ERROR
;
231 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
232 link
.Read
<BRect
>(&fFrame
);
233 fLastUpdate
= system_time();
242 BPrivateScreen::IsValid() const
244 return BPrivateScreen::_IsValid(ID());
249 BPrivateScreen::GetNextID(int32
& id
)
251 BPrivate::AppServerLink link
;
252 link
.StartMessage(AS_GET_NEXT_SCREEN_ID
);
253 link
.Attach
<int32
>(ID());
256 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
257 link
.Read
<int32
>(&id
);
266 BPrivateScreen::WaitForRetrace(bigtime_t timeout
)
268 // Get the retrace semaphore if it's the first time
269 // we are called. Cache the value then.
270 if (!fRetraceSemValid
)
271 fRetraceSem
= _RetraceSemaphore();
273 if (fRetraceSem
< 0) {
274 // syncing to retrace is not supported by the accelerant
280 status
= acquire_sem_etc(fRetraceSem
, 1, B_RELATIVE_TIMEOUT
, timeout
);
281 } while (status
== B_INTERRUPTED
);
288 BPrivateScreen::IndexForColor(uint8 red
, uint8 green
, uint8 blue
, uint8 alpha
)
290 // Looks like this check is necessary
291 if (red
== B_TRANSPARENT_COLOR
.red
292 && green
== B_TRANSPARENT_COLOR
.green
293 && blue
== B_TRANSPARENT_COLOR
.blue
294 && alpha
== B_TRANSPARENT_COLOR
.alpha
)
295 return B_TRANSPARENT_8_BIT
;
297 uint16 index
= ((red
& 0xf8) << 7) | ((green
& 0xf8) << 2) | (blue
>> 3);
299 return fColorMap
->index_map
[index
];
306 BPrivateScreen::ColorForIndex(const uint8 index
)
309 return fColorMap
->color_list
[index
];
316 BPrivateScreen::InvertIndex(uint8 index
)
319 return fColorMap
->inversion_map
[index
];
326 BPrivateScreen::ColorMap()
328 if (fColorMap
== NULL
) {
329 Screens
* screens
= Screens::Default();
330 AutoLocker
<Screens
> locker(screens
);
332 if (fColorMap
!= NULL
) {
333 // someone could have been faster than us
337 // TODO: BeOS R5 here gets the colormap pointer
338 // (with BApplication::ro_offset_to_ptr() ?)
339 // which is contained in a shared area created by the server.
340 BPrivate::AppServerLink link
;
341 link
.StartMessage(AS_SCREEN_GET_COLORMAP
);
342 link
.Attach
<int32
>(ID());
345 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
346 fColorMap
= (color_map
*)malloc(sizeof(color_map
));
347 fOwnsColorMap
= true;
348 link
.Read
<color_map
>(fColorMap
);
357 BPrivateScreen::GetBitmap(BBitmap
**_bitmap
, bool drawCursor
, BRect
* bounds
)
368 BBitmap
* bitmap
= new (std::nothrow
) BBitmap(rect
, ColorSpace());
372 status_t status
= bitmap
->InitCheck();
374 status
= ReadBitmap(bitmap
, drawCursor
, &rect
);
375 if (status
!= B_OK
) {
386 BPrivateScreen::ReadBitmap(BBitmap
* bitmap
, bool drawCursor
, BRect
* bounds
)
397 BPrivate::AppServerLink link
;
398 link
.StartMessage(AS_READ_BITMAP
);
399 link
.Attach
<int32
>(bitmap
->_ServerToken());
400 link
.Attach
<bool>(drawCursor
);
401 link
.Attach
<BRect
>(rect
);
403 status_t status
= B_ERROR
;
404 if (link
.FlushWithReply(status
) < B_OK
|| status
!= B_OK
)
412 BPrivateScreen::DesktopColor(uint32 workspace
)
414 rgb_color color
= { 51, 102, 152, 255 };
415 BPrivate::AppServerLink link
;
417 link
.StartMessage(AS_GET_DESKTOP_COLOR
);
418 link
.Attach
<uint32
>(workspace
);
421 if (link
.FlushWithReply(code
) == B_OK
423 link
.Read
<rgb_color
>(&color
);
430 BPrivateScreen::SetDesktopColor(rgb_color color
, uint32 workspace
,
433 BPrivate::AppServerLink link
;
435 link
.StartMessage(AS_SET_DESKTOP_COLOR
);
436 link
.Attach
<rgb_color
>(color
);
437 link
.Attach
<uint32
>(workspace
);
438 link
.Attach
<bool>(makeDefault
);
444 BPrivateScreen::ProposeMode(display_mode
* target
,
445 const display_mode
* low
, const display_mode
* high
)
447 // We can't return B_BAD_VALUE here, because it's used to indicate
448 // that the mode returned is supported, but it doesn't fall
449 // within the limit (see ProposeMode() documentation)
450 if (target
== NULL
|| low
== NULL
|| high
== NULL
)
453 BPrivate::AppServerLink link
;
454 link
.StartMessage(AS_PROPOSE_MODE
);
455 link
.Attach
<int32
>(ID());
456 link
.Attach
<display_mode
>(*target
);
457 link
.Attach
<display_mode
>(*low
);
458 link
.Attach
<display_mode
>(*high
);
460 status_t status
= B_ERROR
;
461 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
462 link
.Read
<display_mode
>(target
);
465 link
.Read
<bool>(&withinLimits
);
467 status
= B_BAD_VALUE
;
475 BPrivateScreen::GetModeList(display_mode
** _modeList
, uint32
* _count
)
477 if (_modeList
== NULL
|| _count
== NULL
)
480 BPrivate::AppServerLink link
;
481 link
.StartMessage(AS_GET_MODE_LIST
);
482 link
.Attach
<int32
>(ID());
484 status_t status
= B_ERROR
;
485 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
487 if (link
.Read
<uint32
>(&count
) < B_OK
)
490 // TODO: this could get too big for the link
491 int32 size
= count
* sizeof(display_mode
);
492 display_mode
* modeList
= (display_mode
*)malloc(size
);
493 if (modeList
== NULL
)
496 if (link
.Read(modeList
, size
) < B_OK
) {
501 *_modeList
= modeList
;
510 BPrivateScreen::GetMode(uint32 workspace
, display_mode
*mode
)
515 BPrivate::AppServerLink link
;
516 link
.StartMessage(AS_SCREEN_GET_MODE
);
517 link
.Attach
<int32
>(ID());
518 link
.Attach
<uint32
>(workspace
);
520 status_t status
= B_ERROR
;
521 if (link
.FlushWithReply(status
) != B_OK
525 link
.Read
<display_mode
>(mode
);
531 BPrivateScreen::SetMode(uint32 workspace
, display_mode
*mode
, bool makeDefault
)
536 BPrivate::AppServerLink link
;
537 link
.StartMessage(AS_SCREEN_SET_MODE
);
538 link
.Attach
<int32
>(ID());
539 link
.Attach
<uint32
>(workspace
);
540 link
.Attach
<display_mode
>(*mode
);
541 link
.Attach
<bool>(makeDefault
);
543 status_t status
= B_ERROR
;
544 link
.FlushWithReply(status
);
551 BPrivateScreen::GetDeviceInfo(accelerant_device_info
*info
)
556 BPrivate::AppServerLink link
;
557 link
.StartMessage(AS_GET_ACCELERANT_INFO
);
558 link
.Attach
<int32
>(ID());
560 status_t status
= B_ERROR
;
561 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
562 link
.Read
<accelerant_device_info
>(info
);
571 BPrivateScreen::GetMonitorInfo(monitor_info
* info
)
576 BPrivate::AppServerLink link
;
577 link
.StartMessage(AS_GET_MONITOR_INFO
);
578 link
.Attach
<int32
>(ID());
580 status_t status
= B_ERROR
;
581 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
582 link
.Read
<monitor_info
>(info
);
591 BPrivateScreen::GetPixelClockLimits(display_mode
*mode
, uint32
*low
, uint32
*high
)
593 if (mode
== NULL
|| low
== NULL
|| high
== NULL
)
596 BPrivate::AppServerLink link
;
597 link
.StartMessage(AS_GET_PIXEL_CLOCK_LIMITS
);
598 link
.Attach
<int32
>(ID());
599 link
.Attach
<display_mode
>(*mode
);
602 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
603 link
.Read
<uint32
>(low
);
604 link
.Read
<uint32
>(high
);
613 BPrivateScreen::GetTimingConstraints(display_timing_constraints
*constraints
)
615 if (constraints
== NULL
)
618 BPrivate::AppServerLink link
;
619 link
.StartMessage(AS_GET_TIMING_CONSTRAINTS
);
620 link
.Attach
<int32
>(ID());
622 status_t status
= B_ERROR
;
623 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
624 link
.Read
<display_timing_constraints
>(constraints
);
633 BPrivateScreen::SetDPMS(uint32 dpmsState
)
635 BPrivate::AppServerLink link
;
636 link
.StartMessage(AS_SET_DPMS
);
637 link
.Attach
<int32
>(ID());
638 link
.Attach
<uint32
>(dpmsState
);
640 status_t status
= B_ERROR
;
641 link
.FlushWithReply(status
);
648 BPrivateScreen::DPMSState()
652 BPrivate::AppServerLink link
;
653 link
.StartMessage(AS_GET_DPMS_STATE
);
654 link
.Attach
<int32
>(ID());
657 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
)
658 link
.Read
<uint32
>(&state
);
665 BPrivateScreen::DPMSCapabilites()
667 uint32 capabilities
= 0;
669 BPrivate::AppServerLink link
;
670 link
.StartMessage(AS_GET_DPMS_CAPABILITIES
);
671 link
.Attach
<int32
>(ID());
674 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
)
675 link
.Read
<uint32
>(&capabilities
);
682 BPrivateScreen::GetBrightness(float* brightness
)
684 if (brightness
== NULL
)
687 BPrivate::AppServerLink link
;
688 link
.StartMessage(AS_SCREEN_GET_BRIGHTNESS
);
689 link
.Attach
<int32
>(ID());
692 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
)
693 link
.Read
<float>(brightness
);
700 BPrivateScreen::SetBrightness(float brightness
)
702 BPrivate::AppServerLink link
;
703 link
.StartMessage(AS_SCREEN_SET_BRIGHTNESS
);
704 link
.Attach
<int32
>(ID());
705 link
.Attach
<float>(brightness
);
707 status_t status
= B_ERROR
;
708 link
.FlushWithReply(status
);
715 BPrivateScreen::BaseAddress()
717 frame_buffer_config config
;
718 if (_GetFrameBufferConfig(config
) != B_OK
)
721 return config
.frame_buffer
;
726 BPrivateScreen::BytesPerRow()
728 frame_buffer_config config
;
729 if (_GetFrameBufferConfig(config
) != B_OK
)
732 return config
.bytes_per_row
;
736 // #pragma mark - private methods
740 BPrivateScreen::_Acquire()
745 // force an update for the new BScreen object
750 BPrivateScreen::_Release()
752 return --fReferenceCount
== 0;
757 BPrivateScreen::_RetraceSemaphore()
759 BPrivate::AppServerLink link
;
760 link
.StartMessage(AS_GET_RETRACE_SEMAPHORE
);
761 link
.Attach
<int32
>(ID());
763 sem_id id
= B_BAD_SEM_ID
;
764 status_t status
= B_ERROR
;
765 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
766 link
.Read
<sem_id
>(&id
);
767 fRetraceSemValid
= true;
775 BPrivateScreen::_GetFrameBufferConfig(frame_buffer_config
& config
)
777 BPrivate::AppServerLink link
;
778 link
.StartMessage(AS_GET_FRAME_BUFFER_CONFIG
);
779 link
.Attach
<int32
>(ID());
781 status_t status
= B_ERROR
;
782 if (link
.FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
783 link
.Read
<frame_buffer_config
>(&config
);
791 BPrivateScreen::BPrivateScreen(int32 id
)
797 fRetraceSemValid(false),
798 fOwnsColorMap(false),
805 BPrivateScreen::~BPrivateScreen()