1/*
2 * Copyright 2001-2009, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		DarkWyrm <bpmagic@columbus.rr.com>
7 *		Stephan A��mus <superstippi@gmx.de>
8 */
9
10
11/*!	BView/BWindow combination HWInterface implementation */
12
13
14#include "ViewHWInterface.h"
15
16#include <new>
17#include <stdio.h>
18
19#include <Application.h>
20#include <Bitmap.h>
21#include <Cursor.h>
22#include <Locker.h>
23#include <Message.h>
24#include <MessageFilter.h>
25#include <MessageRunner.h>
26#include <Region.h>
27#include <Screen.h>
28#include <String.h>
29#include <View.h>
30#include <Window.h>
31
32#include <ServerProtocol.h>
33
34#include "BBitmapBuffer.h"
35#include "PortLink.h"
36#include "ServerConfig.h"
37#include "ServerCursor.h"
38#include "UpdateQueue.h"
39
40
41#ifdef DEBUG_DRIVER_MODULE
42#	include <stdio.h>
43#	define STRACE(x) printf x
44#else
45#	define STRACE(x) ;
46#endif
47
48
49const unsigned char kEmptyCursor[] = { 16, 1, 0, 0,
50	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
54
55static const bool kDefaultDoubleBuffered = true;
56
57enum {
58	MSG_UPDATE = 'updt'
59};
60
61
62const char*
63string_for_color_space(color_space format)
64{
65	const char* name = "<unkown format>";
66	switch (format) {
67		case B_RGBA64:
68			name = "B_RGBA64";
69			break;
70		case B_RGBA64_BIG:
71			name = "B_RGBA64_BIG";
72			break;
73		case B_RGB48:
74			name = "B_RGB48";
75			break;
76		case B_RGB48_BIG:
77			name = "B_RGB48_BIG";
78			break;
79		case B_RGB32:
80			name = "B_RGB32";
81			break;
82		case B_RGBA32:
83			name = "B_RGBA32";
84			break;
85		case B_RGB32_BIG:
86			name = "B_RGB32_BIG";
87			break;
88		case B_RGBA32_BIG:
89			name = "B_RGBA32_BIG";
90			break;
91		case B_RGB24:
92			name = "B_RGB24";
93			break;
94		case B_RGB24_BIG:
95			name = "B_RGB24_BIG";
96			break;
97		case B_CMAP8:
98			name = "B_CMAP8";
99			break;
100		case B_GRAY8:
101			name = "B_GRAY8";
102			break;
103		case B_GRAY1:
104			name = "B_GRAY1";
105			break;
106		default:
107			break;
108	}
109	return name;
110}
111
112
113static int32
114run_app_thread(void* cookie)
115{
116	if (BApplication* app = (BApplication*)cookie) {
117		app->Lock();
118		app->Run();
119		delete app;
120	}
121	return 0;
122}
123
124
125//#define INPUTSERVER_TEST_MODE 1
126
127
128class CardView : public BView {
129public:
130								CardView(BRect bounds);
131	virtual						~CardView();
132
133	virtual	void				AttachedToWindow();
134	virtual	void				Draw(BRect updateRect);
135	virtual	void				MessageReceived(BMessage* message);
136
137								// CardView
138			void				SetBitmap(const BBitmap* bitmap);
139
140			void				ForwardMessage(BMessage* message = NULL);
141
142private:
143			port_id				fInputPort;
144			const BBitmap*		fBitmap;
145};
146
147class CardWindow : public BWindow {
148public:
149								CardWindow(BRect frame);
150	virtual						~CardWindow();
151
152	virtual	void				MessageReceived(BMessage* message);
153	virtual	bool				QuitRequested();
154
155								// CardWindow
156			void				SetBitmap(const BBitmap* bitmap);
157			void				Invalidate(const BRect& area);
158
159private:
160			CardView*			fView;
161			BRegion				fUpdateRegion;
162			BLocker				fUpdateLock;
163};
164
165class CardMessageFilter : public BMessageFilter {
166public:
167								CardMessageFilter(CardView* view);
168
169	virtual filter_result		Filter(BMessage* message, BHandler** _target);
170
171private:
172			CardView*			fView;
173};
174
175
176//	#pragma mark -
177
178
179CardView::CardView(BRect bounds)
180	:
181	BView(bounds, "graphics card view", B_FOLLOW_ALL, B_WILL_DRAW),
182	fBitmap(NULL)
183{
184	SetViewColor(B_TRANSPARENT_32_BIT);
185
186#ifndef INPUTSERVER_TEST_MODE
187	fInputPort = create_port(200, SERVER_INPUT_PORT);
188#else
189	fInputPort = create_port(100, "ViewInputDevice");
190#endif
191
192#ifdef ENABLE_INPUT_SERVER_EMULATION
193	AddFilter(new CardMessageFilter(this));
194#endif
195}
196
197
198CardView::~CardView()
199{
200}
201
202
203void
204CardView::AttachedToWindow()
205{
206}
207
208
209void
210CardView::Draw(BRect updateRect)
211{
212	if (fBitmap != NULL)
213		DrawBitmapAsync(fBitmap, updateRect, updateRect);
214}
215
216
217/*!	These functions emulate the Input Server by sending the *exact* same kind of
218	messages to the server's port. Being we're using a regular window, it would
219	make little sense to do anything else.
220*/
221void
222CardView::ForwardMessage(BMessage* message)
223{
224	if (message == NULL)
225		message = Window()->CurrentMessage();
226	if (message == NULL)
227		return;
228
229	// remove some fields that potentially mess up our own message processing
230	BMessage copy = *message;
231	copy.RemoveName("screen_where");
232	copy.RemoveName("be:transit");
233	copy.RemoveName("be:view_where");
234	copy.RemoveName("be:cursor_needed");
235	copy.RemoveName("_view_token");
236
237	size_t length = copy.FlattenedSize();
238	char stream[length];
239
240	if (copy.Flatten(stream, length) == B_OK)
241		write_port(fInputPort, 0, stream, length);
242}
243
244
245void
246CardView::MessageReceived(BMessage* message)
247{
248	switch (message->what) {
249		default:
250			BView::MessageReceived(message);
251			break;
252	}
253}
254
255
256void
257CardView::SetBitmap(const BBitmap* bitmap)
258{
259	if (bitmap != fBitmap) {
260		fBitmap = bitmap;
261
262		if (Parent())
263			Invalidate();
264	}
265}
266
267
268//	#pragma mark -
269
270
271CardMessageFilter::CardMessageFilter(CardView* view)
272	:
273	BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
274	fView(view)
275{
276}
277
278
279filter_result
280CardMessageFilter::Filter(BMessage* message, BHandler** target)
281{
282	switch (message->what) {
283		case B_KEY_DOWN:
284		case B_UNMAPPED_KEY_DOWN:
285		case B_KEY_UP:
286		case B_UNMAPPED_KEY_UP:
287		case B_MOUSE_DOWN:
288		case B_MOUSE_UP:
289		case B_MOUSE_WHEEL_CHANGED:
290			if (message->what == B_MOUSE_DOWN)
291				fView->SetMouseEventMask(B_POINTER_EVENTS);
292
293			fView->ForwardMessage(message);
294			return B_SKIP_MESSAGE;
295
296		case B_MOUSE_MOVED:
297		{
298			int32 transit;
299			if (message->FindInt32("be:transit", &transit) == B_OK
300				&& transit == B_ENTERED_VIEW) {
301				// A bug in R5 prevents this call from having an effect if
302				// called elsewhere, and calling it here works, if we're lucky :-)
303				BCursor cursor(kEmptyCursor);
304				fView->SetViewCursor(&cursor, true);
305			}
306			fView->ForwardMessage(message);
307			return B_SKIP_MESSAGE;
308		}
309	}
310
311	return B_DISPATCH_MESSAGE;
312}
313
314
315//	#pragma mark -
316
317
318CardWindow::CardWindow(BRect frame)
319	:
320	BWindow(frame, "Haiku App Server", B_TITLED_WINDOW,
321		B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NO_SERVER_SIDE_WINDOW_MODIFIERS),
322	fUpdateRegion(),
323	fUpdateLock("update lock")
324{
325	fView = new CardView(Bounds());
326	AddChild(fView);
327	fView->MakeFocus();
328		// make it receive key events
329}
330
331
332CardWindow::~CardWindow()
333{
334}
335
336
337void
338CardWindow::MessageReceived(BMessage* msg)
339{
340	STRACE("CardWindow::MessageReceived()\n");
341	switch (msg->what) {
342		case MSG_UPDATE:
343			STRACE("MSG_UPDATE\n");
344			// invalidate all areas in the view that need redrawing
345			if (fUpdateLock.LockWithTimeout(2000LL) >= B_OK) {
346/*				int32 count = fUpdateRegion.CountRects();
347				for (int32 i = 0; i < count; i++) {
348					fView->Invalidate(fUpdateRegion.RectAt(i));
349				}*/
350				BRect frame = fUpdateRegion.Frame();
351				if (frame.IsValid()) {
352					fView->Invalidate(frame);
353//					fView->Invalidate();
354				}
355				fUpdateRegion.MakeEmpty();
356				fUpdateLock.Unlock();
357			} else {
358				// see you next time
359			}
360			break;
361		default:
362			BWindow::MessageReceived(msg);
363			break;
364	}
365	STRACE("CardWindow::MessageReceived() - exit\n");
366}
367
368
369bool
370CardWindow::QuitRequested()
371{
372	port_id serverport = find_port(SERVER_PORT_NAME);
373
374	if (serverport >= 0) {
375		BPrivate::PortLink link(serverport);
376		link.StartMessage(B_QUIT_REQUESTED);
377		link.Flush();
378	} else
379		printf("ERROR: couldn't find the app_server's main port!");
380
381	// we don't quit on ourself, we let us be Quit()!
382	return false;
383}
384
385
386void
387CardWindow::SetBitmap(const BBitmap* bitmap)
388{
389	fView->SetBitmap(bitmap);
390}
391
392
393void
394CardWindow::Invalidate(const BRect& frame)
395{
396	if (LockWithTimeout(1000000) >= B_OK) {
397		fView->Invalidate(frame);
398		Unlock();
399	}
400}
401
402
403//	#pragma mark -
404
405
406ViewHWInterface::ViewHWInterface()
407	:
408	HWInterface(),
409	fBackBuffer(NULL),
410	fFrontBuffer(NULL),
411	fWindow(NULL)
412{
413	SetAsyncDoubleBuffered(kDefaultDoubleBuffered);
414
415	fDisplayMode.virtual_width = 640;
416	fDisplayMode.virtual_height = 480;
417	fDisplayMode.space = B_RGBA32;
418}
419
420
421ViewHWInterface::~ViewHWInterface()
422{
423	if (fWindow) {
424		fWindow->Lock();
425		fWindow->Quit();
426	}
427
428	be_app->Lock();
429	be_app->Quit();
430}
431
432
433status_t
434ViewHWInterface::Initialize()
435{
436	return B_OK;
437}
438
439
440status_t
441ViewHWInterface::Shutdown()
442{
443	return B_OK;
444}
445
446
447status_t
448ViewHWInterface::SetMode(const display_mode& mode)
449{
450	AutoWriteLocker _(this);
451
452	status_t ret = B_OK;
453	// prevent from doing the unnecessary
454	if (fBackBuffer.IsSet() && fFrontBuffer.IsSet()
455		&& fDisplayMode.virtual_width == mode.virtual_width
456		&& fDisplayMode.virtual_height == mode.virtual_height
457		&& fDisplayMode.space == mode.space)
458		return ret;
459
460	// check if we support the mode
461
462	display_mode* modes;
463	uint32 modeCount, i;
464	if (GetModeList(&modes, &modeCount) != B_OK)
465		return B_NO_MEMORY;
466
467	for (i = 0; i < modeCount; i++) {
468		// we only care for the bare minimum
469		if (modes[i].virtual_width == mode.virtual_width
470			&& modes[i].virtual_height == mode.virtual_height
471			&& modes[i].space == mode.space) {
472			// take over settings
473			fDisplayMode = modes[i];
474			break;
475		}
476	}
477
478	delete[] modes;
479
480	if (i == modeCount)
481		return B_BAD_VALUE;
482
483	BRect frame(0.0, 0.0, fDisplayMode.virtual_width - 1,
484		fDisplayMode.virtual_height - 1);
485
486	// create the window if we don't have one already
487	if (!fWindow) {
488		// if the window has not been created yet, the BApplication
489		// has not been created either, but we need one to display
490		// a real BWindow in the test environment.
491		// be_app->Run() needs to be called in another thread
492
493		if (be_app == NULL) {
494			BApplication* app = new BApplication(
495				"application/x-vnd.Haiku-test-app_server");
496			app->Unlock();
497
498			thread_id appThread = spawn_thread(run_app_thread, "app thread",
499				B_NORMAL_PRIORITY, app);
500			if (appThread >= B_OK)
501				ret = resume_thread(appThread);
502			else
503				ret = appThread;
504
505			if (ret < B_OK)
506				return ret;
507		}
508
509		fWindow = new CardWindow(frame.OffsetToCopy(BPoint(50.0, 50.0)));
510
511		// fire up the window thread but don't show it on screen yet
512		fWindow->Hide();
513		fWindow->Show();
514	}
515
516	if (fWindow->Lock()) {
517		// just to be save
518		fWindow->SetBitmap(NULL);
519
520		// free and reallocate the bitmaps while the window is locked,
521		// so that the view does not accidentally draw a freed bitmap
522		fBackBuffer.Unset();
523		fFrontBuffer.Unset();
524
525		// NOTE: backbuffer is always B_RGBA32, this simplifies the
526		// drawing backend implementation tremendously for the time
527		// being. The color space conversion is handled in CopyBackToFront()
528
529		// TODO: Above not true anymore for single buffered mode!!!
530		// -> fall back to double buffer for fDisplayMode.space != B_RGB32
531		// as intermediate solution...
532		bool doubleBuffered = true;
533		if ((color_space)fDisplayMode.space != B_RGB32
534			&& (color_space)fDisplayMode.space != B_RGBA32)
535			doubleBuffered = true;
536
537		BBitmap* frontBitmap
538			= new BBitmap(frame, 0, (color_space)fDisplayMode.space);
539		fFrontBuffer.SetTo(new BBitmapBuffer(frontBitmap));
540
541		status_t err = fFrontBuffer->InitCheck();
542		if (err < B_OK) {
543			fFrontBuffer.Unset();
544			ret = err;
545		}
546
547		if (err >= B_OK && doubleBuffered) {
548			// backbuffer is always B_RGBA32
549			// since we override IsDoubleBuffered(), the drawing buffer
550			// is in effect also always B_RGBA32.
551			BBitmap* backBitmap = new BBitmap(frame, 0, B_RGBA32);
552			fBackBuffer.SetTo(new BBitmapBuffer(backBitmap));
553
554			err = fBackBuffer->InitCheck();
555			if (err < B_OK) {
556				fBackBuffer.Unset();
557				ret = err;
558			}
559		}
560
561		_NotifyFrameBufferChanged();
562
563		if (ret >= B_OK) {
564			// clear out buffers, alpha is 255 this way
565			// TODO: maybe this should handle different color spaces in different ways
566			if (fBackBuffer.IsSet())
567				memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength());
568			memset(fFrontBuffer->Bits(), 255, fFrontBuffer->BitsLength());
569
570			// change the window size and update the bitmap used for drawing
571			fWindow->ResizeTo(frame.Width(), frame.Height());
572			fWindow->SetBitmap(fFrontBuffer->Bitmap());
573		}
574
575		// window is hidden when this function is called the first time
576		if (fWindow->IsHidden())
577			fWindow->Show();
578
579		fWindow->Unlock();
580	} else {
581		ret = B_ERROR;
582	}
583	return ret;
584}
585
586
587void
588ViewHWInterface::GetMode(display_mode* mode)
589{
590	if (mode && ReadLock()) {
591		*mode = fDisplayMode;
592		ReadUnlock();
593	}
594}
595
596
597status_t
598ViewHWInterface::GetDeviceInfo(accelerant_device_info* info)
599{
600	// We really don't have to provide anything here because this is strictly
601	// a software-only driver, but we'll have some fun, anyway.
602	if (ReadLock()) {
603		info->version = 100;
604		sprintf(info->name, "Haiku, Inc. ViewHWInterface");
605		sprintf(info->chipset, "Haiku, Inc. Chipset");
606		sprintf(info->serial_no, "3.14159265358979323846");
607		info->memory = 134217728;	// 128 MB, not that we really have that much. :)
608		info->dac_speed = 0xFFFFFFFF;	// *heh*
609
610		ReadUnlock();
611	}
612
613	return B_OK;
614}
615
616
617status_t
618ViewHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
619{
620	if (!fFrontBuffer.IsSet())
621		return B_ERROR;
622
623	config.frame_buffer = fFrontBuffer->Bits();
624	config.frame_buffer_dma = NULL;
625	config.bytes_per_row = fFrontBuffer->BytesPerRow();
626
627	return B_OK;
628}
629
630
631status_t
632ViewHWInterface::GetModeList(display_mode** _modes, uint32* _count)
633{
634	AutoReadLocker _(this);
635
636#if 1
637	// setup a whole bunch of different modes
638	const struct resolution { int32 width, height; } resolutions[] = {
639		{640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960},
640		{1280, 1024}, {1400, 1050}, {1600, 1200}
641	};
642	uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]);
643	const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32};
644	uint32 count = resolutionCount * 4;
645
646	display_mode* modes = new(std::nothrow) display_mode[count];
647	if (modes == NULL)
648		return B_NO_MEMORY;
649
650	*_modes = modes;
651	*_count = count;
652
653	int32 index = 0;
654	for (uint32 i = 0; i < resolutionCount; i++) {
655		for (uint32 c = 0; c < 4; c++) {
656			modes[index].virtual_width = resolutions[i].width;
657			modes[index].virtual_height = resolutions[i].height;
658			modes[index].space = colors[c];
659
660			modes[index].h_display_start = 0;
661			modes[index].v_display_start = 0;
662			modes[index].timing.h_display = resolutions[i].width;
663			modes[index].timing.v_display = resolutions[i].height;
664			modes[index].timing.h_total = 22000;
665			modes[index].timing.v_total = 22000;
666			modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total
667				* modes[index].timing.v_total * 60) / 1000;
668			modes[index].flags = B_PARALLEL_ACCESS;
669
670			index++;
671		}
672	}
673#else
674	// support only a single mode, useful
675	// for testing a specific mode
676	display_mode *modes = new(nothrow) display_mode[1];
677	modes[0].virtual_width = 640;
678	modes[0].virtual_height = 480;
679	modes[0].space = B_CMAP8;
680
681	*_modes = modes;
682	*_count = 1;
683#endif
684
685	return B_OK;
686}
687
688
689status_t
690ViewHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
691	uint32* high)
692{
693	return B_ERROR;
694}
695
696
697status_t
698ViewHWInterface::GetTimingConstraints(display_timing_constraints* constraints)
699{
700	return B_ERROR;
701}
702
703
704status_t
705ViewHWInterface::ProposeMode(display_mode* candidate, const display_mode* low,
706	const display_mode* high)
707{
708	// We should be able to get away with this because we're not dealing with
709	// any specific hardware. This is a Good Thing(TM) because we can support
710	// any hardware we wish within reasonable expectaions and programmer
711	// laziness. :P
712	return B_OK;
713}
714
715
716status_t
717ViewHWInterface::SetDPMSMode(uint32 state)
718{
719	AutoWriteLocker _(this);
720
721	return BScreen().SetDPMS(state);
722}
723
724
725uint32
726ViewHWInterface::DPMSMode()
727{
728	AutoReadLocker _(this);
729
730	return BScreen().DPMSState();
731}
732
733
734uint32
735ViewHWInterface::DPMSCapabilities()
736{
737	AutoReadLocker _(this);
738
739	return BScreen().DPMSCapabilites();
740}
741
742
743status_t
744ViewHWInterface::SetBrightness(float brightness)
745{
746	AutoReadLocker _(this);
747
748	return BScreen().SetBrightness(brightness);
749}
750
751
752status_t
753ViewHWInterface::GetBrightness(float* brightness)
754{
755	AutoReadLocker _(this);
756
757	return BScreen().GetBrightness(brightness);
758}
759
760
761sem_id
762ViewHWInterface::RetraceSemaphore()
763{
764	return -1;
765}
766
767
768status_t
769ViewHWInterface::WaitForRetrace(bigtime_t timeout)
770{
771	// Locking shouldn't be necessary here - R5 should handle this for us. :)
772	BScreen screen;
773	return screen.WaitForRetrace(timeout);
774}
775
776
777RenderingBuffer*
778ViewHWInterface::FrontBuffer() const
779{
780	return fFrontBuffer.Get();
781}
782
783
784RenderingBuffer*
785ViewHWInterface::BackBuffer() const
786{
787	return fBackBuffer.Get();
788}
789
790
791bool
792ViewHWInterface::IsDoubleBuffered() const
793{
794	if (fFrontBuffer.IsSet())
795		return fBackBuffer.IsSet();
796
797	return false;
798}
799
800
801status_t
802ViewHWInterface::Invalidate(const BRect& frame)
803{
804	status_t ret = HWInterface::Invalidate(frame);
805
806	if (ret >= B_OK && fWindow && !IsDoubleBuffered())
807		fWindow->Invalidate(frame);
808	return ret;
809}
810
811
812status_t
813ViewHWInterface::CopyBackToFront(const BRect& frame)
814{
815	status_t ret = HWInterface::CopyBackToFront(frame);
816
817	if (ret >= B_OK && fWindow)
818		fWindow->Invalidate(frame);
819	return ret;
820}
821