btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / interface / PrivateScreen.cpp
blobce061735b7299293a7a912e27d55877d671bfd80
1 /*
2 * Copyright 2002-2009, Haiku Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stefano Ceccherini (burton666@libero.it)
7 * Axel Dörfler, axeld@pinc-software.de
8 */
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>
18 #include <new>
19 #include <pthread.h>
20 #include <stdlib.h>
22 #include <Application.h>
23 #include <Autolock.h>
24 #include <Bitmap.h>
25 #include <Locker.h>
26 #include <ObjectList.h>
27 #include <Window.h>
29 #include <AutoLocker.h>
31 #include <AppMisc.h>
32 #include <AppServerLink.h>
33 #include <ServerProtocol.h>
36 using namespace BPrivate;
39 namespace {
41 struct Screens {
42 BObjectList<BPrivateScreen> list;
44 Screens()
46 list(2, true),
47 fLock("screen list")
51 bool Lock()
53 return fLock.Lock();
56 void Unlock()
58 fLock.Unlock();
61 static Screens* Default()
63 if (sDefaultInstance == NULL)
64 pthread_once(&sDefaultInitOnce, &_InitSingleton);
66 return sDefaultInstance;
69 private:
70 static void _InitSingleton()
72 sDefaultInstance = new Screens;
75 private:
76 BLocker fLock;
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
88 BPrivateScreen*
89 BPrivateScreen::Get(BWindow* window)
91 int32 id = B_MAIN_SCREEN_ID.id;
93 if (window != NULL) {
94 BPrivate::AppServerLink link;
95 link.StartMessage(AS_GET_SCREEN_ID_FROM_WINDOW);
96 link.Attach<int32>(_get_object_token_(window));
98 status_t status;
99 if (link.FlushWithReply(status) == B_OK && status == B_OK)
100 link.Read<int32>(&id);
103 return _Get(id, false);
107 BPrivateScreen*
108 BPrivateScreen::Get(int32 id)
110 return _Get(id, true);
114 BPrivateScreen*
115 BPrivateScreen::_Get(int32 id, bool check)
117 // Nothing works without an app_server connection
118 if (be_app == NULL)
119 return NULL;
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) {
130 screen->_Acquire();
131 return screen;
135 if (check) {
136 // check if ID is valid
137 if (!_IsValid(id))
138 return NULL;
141 // we need to allocate a new one
143 BPrivateScreen* screen = new (std::nothrow) BPrivateScreen(id);
144 if (screen == NULL)
145 return NULL;
147 screens->list.AddItem(screen);
148 return screen;
152 void
153 BPrivateScreen::Put(BPrivateScreen* screen)
155 if (screen == NULL)
156 return;
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);
171 BPrivateScreen*
172 BPrivateScreen::GetNext(BPrivateScreen* screen)
174 Screens* screens = Screens::Default();
175 AutoLocker<Screens> locker(screens);
177 int32 id;
178 status_t status = screen->GetNextID(id);
179 if (status != B_OK)
180 return NULL;
182 BPrivateScreen* nextScreen = Get(id);
183 if (nextScreen == NULL)
184 return NULL;
186 Put(screen);
187 return nextScreen;
191 bool
192 BPrivateScreen::_IsValid(int32 id)
194 BPrivate::AppServerLink link;
195 link.StartMessage(AS_VALID_SCREEN_ID);
196 link.Attach<int32>(id);
198 status_t status;
199 if (link.FlushWithReply(status) != B_OK || status < B_OK)
200 return false;
202 return true;
206 // #pragma mark -
209 color_space
210 BPrivateScreen::ColorSpace()
212 display_mode mode;
213 if (GetMode(B_CURRENT_WORKSPACE_INDEX, &mode) == B_OK)
214 return (color_space)mode.space;
216 return B_NO_COLOR_SPACE;
220 BRect
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();
237 return fFrame;
241 bool
242 BPrivateScreen::IsValid() const
244 return BPrivateScreen::_IsValid(ID());
248 status_t
249 BPrivateScreen::GetNextID(int32& id)
251 BPrivate::AppServerLink link;
252 link.StartMessage(AS_GET_NEXT_SCREEN_ID);
253 link.Attach<int32>(ID());
255 status_t status;
256 if (link.FlushWithReply(status) == B_OK && status == B_OK) {
257 link.Read<int32>(&id);
258 return B_OK;
261 return status;
265 status_t
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
275 return fRetraceSem;
278 status_t status;
279 do {
280 status = acquire_sem_etc(fRetraceSem, 1, B_RELATIVE_TIMEOUT, timeout);
281 } while (status == B_INTERRUPTED);
283 return status;
287 uint8
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);
298 if (ColorMap())
299 return fColorMap->index_map[index];
301 return 0;
305 rgb_color
306 BPrivateScreen::ColorForIndex(const uint8 index)
308 if (ColorMap())
309 return fColorMap->color_list[index];
311 return rgb_color();
315 uint8
316 BPrivateScreen::InvertIndex(uint8 index)
318 if (ColorMap())
319 return fColorMap->inversion_map[index];
321 return 0;
325 const color_map*
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
334 return fColorMap;
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());
344 status_t status;
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);
352 return fColorMap;
356 status_t
357 BPrivateScreen::GetBitmap(BBitmap**_bitmap, bool drawCursor, BRect* bounds)
359 if (_bitmap == NULL)
360 return B_BAD_VALUE;
362 BRect rect;
363 if (bounds != NULL)
364 rect = *bounds;
365 else
366 rect = Frame();
368 BBitmap* bitmap = new (std::nothrow) BBitmap(rect, ColorSpace());
369 if (bitmap == NULL)
370 return B_NO_MEMORY;
372 status_t status = bitmap->InitCheck();
373 if (status == B_OK)
374 status = ReadBitmap(bitmap, drawCursor, &rect);
375 if (status != B_OK) {
376 delete bitmap;
377 return status;
380 *_bitmap = bitmap;
381 return B_OK;
385 status_t
386 BPrivateScreen::ReadBitmap(BBitmap* bitmap, bool drawCursor, BRect* bounds)
388 if (bitmap == NULL)
389 return B_BAD_VALUE;
391 BRect rect;
392 if (bounds != NULL)
393 rect = *bounds;
394 else
395 rect = Frame();
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)
405 return status;
407 return B_OK;
411 rgb_color
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);
420 int32 code;
421 if (link.FlushWithReply(code) == B_OK
422 && code == B_OK)
423 link.Read<rgb_color>(&color);
425 return color;
429 void
430 BPrivateScreen::SetDesktopColor(rgb_color color, uint32 workspace,
431 bool makeDefault)
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);
439 link.Flush();
443 status_t
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)
451 return B_ERROR;
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);
464 bool withinLimits;
465 link.Read<bool>(&withinLimits);
466 if (!withinLimits)
467 status = B_BAD_VALUE;
470 return status;
474 status_t
475 BPrivateScreen::GetModeList(display_mode** _modeList, uint32* _count)
477 if (_modeList == NULL || _count == NULL)
478 return B_BAD_VALUE;
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) {
486 uint32 count;
487 if (link.Read<uint32>(&count) < B_OK)
488 return B_ERROR;
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)
494 return B_NO_MEMORY;
496 if (link.Read(modeList, size) < B_OK) {
497 free(modeList);
498 return B_ERROR;
501 *_modeList = modeList;
502 *_count = count;
505 return status;
509 status_t
510 BPrivateScreen::GetMode(uint32 workspace, display_mode *mode)
512 if (mode == NULL)
513 return B_BAD_VALUE;
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
522 || status != B_OK)
523 return status;
525 link.Read<display_mode>(mode);
526 return B_OK;
530 status_t
531 BPrivateScreen::SetMode(uint32 workspace, display_mode *mode, bool makeDefault)
533 if (mode == NULL)
534 return B_BAD_VALUE;
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);
546 return status;
550 status_t
551 BPrivateScreen::GetDeviceInfo(accelerant_device_info *info)
553 if (info == NULL)
554 return B_BAD_VALUE;
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);
563 return B_OK;
566 return status;
570 status_t
571 BPrivateScreen::GetMonitorInfo(monitor_info* info)
573 if (info == NULL)
574 return B_BAD_VALUE;
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);
583 return B_OK;
586 return status;
590 status_t
591 BPrivateScreen::GetPixelClockLimits(display_mode *mode, uint32 *low, uint32 *high)
593 if (mode == NULL || low == NULL || high == NULL)
594 return B_BAD_VALUE;
596 BPrivate::AppServerLink link;
597 link.StartMessage(AS_GET_PIXEL_CLOCK_LIMITS);
598 link.Attach<int32>(ID());
599 link.Attach<display_mode>(*mode);
601 status_t status;
602 if (link.FlushWithReply(status) == B_OK && status == B_OK) {
603 link.Read<uint32>(low);
604 link.Read<uint32>(high);
605 return B_OK;
608 return status;
612 status_t
613 BPrivateScreen::GetTimingConstraints(display_timing_constraints *constraints)
615 if (constraints == NULL)
616 return B_BAD_VALUE;
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);
625 return B_OK;
628 return status;
632 status_t
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);
643 return status;
647 uint32
648 BPrivateScreen::DPMSState()
650 uint32 state = 0;
652 BPrivate::AppServerLink link;
653 link.StartMessage(AS_GET_DPMS_STATE);
654 link.Attach<int32>(ID());
656 status_t status;
657 if (link.FlushWithReply(status) == B_OK && status == B_OK)
658 link.Read<uint32>(&state);
660 return state;
664 uint32
665 BPrivateScreen::DPMSCapabilites()
667 uint32 capabilities = 0;
669 BPrivate::AppServerLink link;
670 link.StartMessage(AS_GET_DPMS_CAPABILITIES);
671 link.Attach<int32>(ID());
673 status_t status;
674 if (link.FlushWithReply(status) == B_OK && status == B_OK)
675 link.Read<uint32>(&capabilities);
677 return capabilities;
681 status_t
682 BPrivateScreen::GetBrightness(float* brightness)
684 if (brightness == NULL)
685 return B_BAD_VALUE;
687 BPrivate::AppServerLink link;
688 link.StartMessage(AS_SCREEN_GET_BRIGHTNESS);
689 link.Attach<int32>(ID());
691 status_t status;
692 if (link.FlushWithReply(status) == B_OK && status == B_OK)
693 link.Read<float>(brightness);
695 return status;
699 status_t
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);
710 return status;
714 void *
715 BPrivateScreen::BaseAddress()
717 frame_buffer_config config;
718 if (_GetFrameBufferConfig(config) != B_OK)
719 return NULL;
721 return config.frame_buffer;
725 uint32
726 BPrivateScreen::BytesPerRow()
728 frame_buffer_config config;
729 if (_GetFrameBufferConfig(config) != B_OK)
730 return 0;
732 return config.bytes_per_row;
736 // #pragma mark - private methods
739 void
740 BPrivateScreen::_Acquire()
742 fReferenceCount++;
744 fLastUpdate = 0;
745 // force an update for the new BScreen object
749 bool
750 BPrivateScreen::_Release()
752 return --fReferenceCount == 0;
756 sem_id
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;
770 return id;
774 status_t
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);
784 return B_OK;
787 return status;
791 BPrivateScreen::BPrivateScreen(int32 id)
793 fID(id),
794 fReferenceCount(0),
795 fColorMap(NULL),
796 fRetraceSem(-1),
797 fRetraceSemValid(false),
798 fOwnsColorMap(false),
799 fFrame(0, 0, 0, 0),
800 fLastUpdate(0)
805 BPrivateScreen::~BPrivateScreen()
807 if (fOwnsColorMap)
808 free(fColorMap);