1/*
2 * Copyright 2005-2022 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		Augustin Cavalier <waddlesplash>
7 *		DarkWyrm <bpmagic@columbus.rr.com>
8 *		Ren�� Gollent
9 *		John Scipione, jscipione@gmail.com
10 *		Wim van der Meer <WPJvanderMeer@gmail.com>
11 */
12
13
14#include <ctype.h>
15#include <stdio.h>
16#include <time.h>
17#include <unistd.h>
18
19#include <algorithm>
20#include <map>
21#include <string>
22
23#include <AboutWindow.h>
24#include <AppDefs.h>
25#include <AppFileInfo.h>
26#include <Application.h>
27#include <Bitmap.h>
28#include <ColorConversion.h>
29#include <ControlLook.h>
30#include <DateTimeFormat.h>
31#include <Dragger.h>
32#include <DurationFormat.h>
33#include <File.h>
34#include <FindDirectory.h>
35#include <Font.h>
36#include <fs_attr.h>
37#include <LayoutBuilder.h>
38#include <MessageRunner.h>
39#include <Messenger.h>
40#include <NumberFormat.h>
41#include <ObjectList.h>
42#include <OS.h>
43#include <Path.h>
44#include <PathFinder.h>
45#include <PopUpMenu.h>
46#include <Resources.h>
47#include <Screen.h>
48#include <ScrollView.h>
49#include <String.h>
50#include <StringFormat.h>
51#include <StringList.h>
52#include <StringView.h>
53#include <TextView.h>
54#include <TranslationUtils.h>
55#include <TranslatorFormats.h>
56#include <View.h>
57#include <ViewPrivate.h>
58#include <Volume.h>
59#include <VolumeRoster.h>
60#include <Window.h>
61#include <WindowPrivate.h>
62
63#include <AppMisc.h>
64#include <AutoDeleter.h>
65#include <AutoDeleterPosix.h>
66#include <cpu_type.h>
67#include <parsedate.h>
68#include <system_revision.h>
69
70#include <Catalog.h>
71#include <Language.h>
72#include <Locale.h>
73#include <LocaleRoster.h>
74
75#include "HyperTextActions.h"
76#include "HyperTextView.h"
77#include "Utilities.h"
78
79#include "Credits.h"
80
81
82#ifndef LINE_MAX
83#define LINE_MAX 2048
84#endif
85
86
87#undef B_TRANSLATION_CONTEXT
88#define B_TRANSLATION_CONTEXT "AboutWindow"
89
90
91static const char* kSignature = "application/x-vnd.Haiku-About";
92
93static const float kWindowWidth = 500.0f;
94static const float kWindowHeight = 300.0f;
95
96static const float kSysInfoMinWidth = 163.0f;
97static const float kSysInfoMinHeight = 193.0f;
98
99static const float kDraggerMargin = 6.0f;
100
101static const int32 kMsgScrollCreditsView = 'mviv';
102
103static int ignored_pages(system_info*);
104static int max_pages(system_info*);
105static int max_and_ignored_pages(system_info*);
106static int used_pages(system_info*);
107
108static const rgb_color kIdealHaikuGreen = { 42, 131, 36, 255 };
109static const rgb_color kIdealHaikuOrange = { 255, 69, 0, 255 };
110static const rgb_color kIdealHaikuYellow = { 255, 176, 0, 255 };
111static const rgb_color kIdealBeOSBlue = { 0, 0, 200, 255 };
112static const rgb_color kIdealBeOSRed = { 200, 0, 0, 255 };
113
114static const char* kBSDTwoClause = B_TRANSLATE_MARK("BSD (2-clause)");
115static const char* kBSDThreeClause = B_TRANSLATE_MARK("BSD (3-clause)");
116static const char* kBSDFourClause = B_TRANSLATE_MARK("BSD (4-clause)");
117static const char* kGPLv2 = B_TRANSLATE_MARK("GNU GPL v2");
118static const char* kGPLv3 = B_TRANSLATE_MARK("GNU GPL v3");
119static const char* kLGPLv2 = B_TRANSLATE_MARK("GNU LGPL v2");
120static const char* kLGPLv21 = B_TRANSLATE_MARK("GNU LGPL v2.1");
121#if 0
122static const char* kPublicDomain = B_TRANSLATE_MARK("Public Domain");
123#endif
124#ifdef __i386__
125static const char* kIntel2xxxFirmware = B_TRANSLATE_MARK("Intel (2xxx firmware)");
126static const char* kIntelFirmware = B_TRANSLATE_MARK("Intel WiFi Firmware");
127static const char* kMarvellFirmware = B_TRANSLATE_MARK("Marvell (firmware)");
128static const char* kRalinkFirmware = B_TRANSLATE_MARK("Ralink WiFi Firmware");
129#endif
130
131
132//	#pragma mark - TranslationComparator function
133
134
135static int
136TranslationComparator(const void* left, const void* right)
137{
138	const Translation* leftTranslation = *(const Translation**)left;
139	const Translation* rightTranslation = *(const Translation**)right;
140
141	BLanguage* language;
142	BString leftName;
143	if (BLocaleRoster::Default()->GetLanguage(leftTranslation->languageCode,
144			&language) == B_OK) {
145		language->GetName(leftName);
146		delete language;
147	} else
148		leftName = leftTranslation->languageCode;
149
150	BString rightName;
151	if (BLocaleRoster::Default()->GetLanguage(rightTranslation->languageCode,
152			&language) == B_OK) {
153		language->GetName(rightName);
154		delete language;
155	} else
156		rightName = rightTranslation->languageCode;
157
158	BCollator collator;
159	BLocale::Default()->GetCollator(&collator);
160	return collator.Compare(leftName.String(), rightName.String());
161}
162
163
164//	#pragma mark - class definitions
165
166
167class AboutApp : public BApplication {
168public:
169							AboutApp();
170			void			MessageReceived(BMessage* message);
171};
172
173
174class AboutView;
175
176class AboutWindow : public BWindow {
177public:
178							AboutWindow();
179
180	virtual	bool			QuitRequested();
181
182			AboutView*		fAboutView;
183};
184
185
186class LogoView : public BView {
187public:
188							LogoView();
189	virtual					~LogoView();
190
191	virtual	BSize			MinSize();
192	virtual	BSize			MaxSize();
193
194	virtual void			Draw(BRect updateRect);
195
196private:
197			BBitmap*		fLogo;
198};
199
200
201class CropView : public BView {
202public:
203							CropView(BView* target, int32 left, int32 top,
204								int32 right, int32 bottom);
205	virtual					~CropView();
206
207	virtual	BSize			MinSize();
208	virtual	BSize			MaxSize();
209
210	virtual void			DoLayout();
211
212private:
213			BView*			fTarget;
214			int32			fCropLeft;
215			int32			fCropTop;
216			int32			fCropRight;
217			int32			fCropBottom;
218};
219
220
221class SysInfoDragger : public BDragger {
222public:
223							SysInfoDragger(BView* target);
224
225	virtual	void			MessageReceived(BMessage* message);
226
227private:
228			BView*			fTarget;
229};
230
231
232class SysInfoView : public BView {
233public:
234							SysInfoView();
235	virtual					~SysInfoView();
236
237	virtual	status_t		Archive(BMessage* archive, bool deep = true) const;
238	static	BArchivable*	Instantiate(BMessage* archive);
239
240	virtual	void			AttachedToWindow();
241	virtual	void			AllAttached();
242	virtual	void			Draw(BRect);
243	virtual void			MessageReceived(BMessage* message);
244	virtual void			Pulse();
245
246			void			CacheInitialSize();
247
248			float			MinWidth() const { return fCachedMinWidth; };
249			float			MinHeight() const { return fCachedMinHeight; };
250
251private:
252			void			_AdjustColors();
253			void			_AdjustTextColors() const;
254			rgb_color		_DesktopTextColor(int32 workspace = -1) const;
255			bool			_OnDesktop() const;
256			void			_ResizeBy(float, float);
257			void			_ResizeTo(float, float);
258
259			BStringView*	_CreateLabel(const char*, const char*);
260			void			_UpdateLabel(BStringView*);
261			BStringView*	_CreateSubtext(const char*, const char*);
262			void			_UpdateSubtext(BStringView*);
263			void			_UpdateText(BTextView*);
264			void			_CreateDragger();
265
266			float			_BaseWidth();
267			float			_BaseHeight();
268
269			BString			_GetOSVersion();
270			BString			_GetABIVersion();
271			BString			_GetCPUCount(system_info*);
272			BString			_GetCPUInfo();
273			BString			_GetCPUFrequency();
274			BString			_GetRamSize(system_info*);
275			BString			_GetRamUsage(system_info*);
276			BString			_GetKernelDateTime(system_info*);
277			BString			_GetUptime();
278
279			float			_UptimeHeight();
280
281private:
282			rgb_color		fDesktopTextColor;
283
284			BStringView*	fVersionLabelView;
285			BStringView*	fVersionInfoView;
286			BStringView*	fCPULabelView;
287			BStringView*	fCPUInfoView;
288			BStringView*	fMemSizeView;
289			BStringView*	fMemUsageView;
290			BStringView*	fKernelDateTimeView;
291			BTextView*		fUptimeView;
292
293			BDragger*		fDragger;
294
295			BNumberFormat	fNumberFormat;
296
297			float			fCachedBaseWidth;
298			float			fCachedMinWidth;
299			float			fCachedBaseHeight;
300			float			fCachedMinHeight;
301
302	static const uint8		kLabelCount = 5;
303	static const uint8		kSubtextCount = 5;
304};
305
306
307class AboutView : public BView {
308public:
309							AboutView();
310							~AboutView();
311
312	virtual void			AttachedToWindow();
313	virtual void			Pulse();
314	virtual void			MessageReceived(BMessage* message);
315	virtual void			MouseDown(BPoint where);
316
317			void			AddCopyrightEntry(const char* name,
318								const char* text,
319								const StringVector& licenses,
320								const StringVector& sources,
321								const char* url);
322			void			AddCopyrightEntry(const char* name,
323								const char* text, const char* url = NULL);
324			void			PickRandomHaiku();
325
326private:
327	typedef std::map<std::string, PackageCredit*> PackageCreditMap;
328
329			void			_CreateScrollRunner();
330			LogoView*		_CreateLogoView();
331			SysInfoView*	_CreateSysInfoView();
332			CropView*		_CreateCreditsView();
333			status_t		_GetLicensePath(const char* license,
334								BPath& path);
335			void			_AddCopyrightsFromAttribute();
336			void			_AddPackageCredit(const PackageCredit& package);
337			void			_AddPackageCreditEntries();
338
339
340private:
341			LogoView*		fLogoView;
342			SysInfoView*	fSysInfoView;
343			HyperTextView*	fCreditsView;
344
345			bigtime_t		fLastActionTime;
346			BMessageRunner*	fScrollRunner;
347
348			float			fCachedMinWidth;
349			float			fCachedMinHeight;
350
351			PackageCreditMap fPackageCredits;
352
353private:
354			rgb_color		fTextColor;
355			rgb_color		fLinkColor;
356			rgb_color		fHaikuOrangeColor;
357			rgb_color		fHaikuGreenColor;
358			rgb_color		fHaikuYellowColor;
359			rgb_color		fBeOSRedColor;
360			rgb_color		fBeOSBlueColor;
361};
362
363
364//	#pragma mark - AboutApp
365
366
367AboutApp::AboutApp()
368	:
369	BApplication(kSignature)
370{
371	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("AboutSystem");
372
373	AboutWindow* window = new(std::nothrow) AboutWindow();
374	if (window != NULL)
375		window->Show();
376}
377
378
379void
380AboutApp::MessageReceived(BMessage* message)
381{
382	switch (message->what) {
383		case B_SILENT_RELAUNCH:
384			WindowAt(0)->Activate();
385			break;
386	}
387
388	BApplication::MessageReceived(message);
389}
390
391
392//	#pragma mark - AboutWindow
393
394
395AboutWindow::AboutWindow()
396	:
397	BWindow(BRect(0, 0, kWindowWidth, kWindowHeight),
398		B_TRANSLATE("About this system"), B_TITLED_WINDOW,
399		B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE)
400{
401	SetLayout(new BGroupLayout(B_VERTICAL, 0));
402
403	fAboutView = new AboutView();
404	AddChild(fAboutView);
405
406	CenterOnScreen();
407}
408
409
410bool
411AboutWindow::QuitRequested()
412{
413	be_app->PostMessage(B_QUIT_REQUESTED);
414	return true;
415}
416
417
418#undef B_TRANSLATION_CONTEXT
419#define B_TRANSLATION_CONTEXT "AboutView"
420
421
422//	#pragma mark - LogoView
423
424
425LogoView::LogoView()
426	:
427	BView("logo", B_WILL_DRAW)
428{
429	SetDrawingMode(B_OP_OVER);
430
431#ifdef HAIKU_DISTRO_COMPATIBILITY_OFFICIAL
432	rgb_color bgColor = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
433	if (bgColor.IsLight())
434		fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo.png");
435	else
436		fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "logo_dark.png");
437#else
438	fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "walter_logo.png");
439#endif
440
441	// Set view color to panel background color when fLogo is NULL
442	// to prevent a white pixel from being drawn.
443	if (fLogo == NULL)
444		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
445}
446
447
448LogoView::~LogoView()
449{
450	delete fLogo;
451}
452
453
454BSize
455LogoView::MinSize()
456{
457	if (fLogo == NULL)
458		return BSize(0, 0);
459
460	return BSize(fLogo->Bounds().Width(), fLogo->Bounds().Height());
461}
462
463
464BSize
465LogoView::MaxSize()
466{
467	if (fLogo == NULL)
468		return BSize(0, 0);
469
470	return BSize(B_SIZE_UNLIMITED, fLogo->Bounds().Height());
471}
472
473
474void
475LogoView::Draw(BRect updateRect)
476{
477	if (fLogo == NULL)
478		return;
479
480	BRect bounds(Bounds());
481	SetLowColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR));
482	FillRect(bounds, B_SOLID_LOW);
483
484	DrawBitmap(fLogo, BPoint((bounds.Width() - fLogo->Bounds().Width()) / 2, 0));
485}
486
487
488//	#pragma mark - CropView
489
490
491CropView::CropView(BView* target, int32 left, int32 top, int32 right,
492	int32 bottom)
493	:
494	BView("crop view", 0),
495	fTarget(target),
496	fCropLeft(left),
497	fCropTop(top),
498	fCropRight(right),
499	fCropBottom(bottom)
500{
501	AddChild(target);
502}
503
504
505CropView::~CropView()
506{
507}
508
509
510BSize
511CropView::MinSize()
512{
513	if (fTarget == NULL)
514		return BSize();
515
516	BSize size = fTarget->MinSize();
517	if (size.width != B_SIZE_UNSET)
518		size.width -= fCropLeft + fCropRight;
519	if (size.height != B_SIZE_UNSET)
520		size.height -= fCropTop + fCropBottom;
521
522	return size;
523}
524
525
526BSize
527CropView::MaxSize()
528{
529	if (fTarget == NULL)
530		return BSize();
531
532	BSize size = fTarget->MaxSize();
533	if (size.width != B_SIZE_UNSET)
534		size.width -= fCropLeft + fCropRight;
535	if (size.height != B_SIZE_UNSET)
536		size.height -= fCropTop + fCropBottom;
537
538	return size;
539}
540
541
542void
543CropView::DoLayout()
544{
545	BView::DoLayout();
546
547	if (fTarget == NULL)
548		return;
549
550	fTarget->MoveTo(-fCropLeft, -fCropTop);
551	fTarget->ResizeTo(Bounds().Width() + fCropLeft + fCropRight,
552		Bounds().Height() + fCropTop + fCropBottom);
553}
554
555
556//	#pragma mark - SysInfoDragger
557
558
559SysInfoDragger::SysInfoDragger(BView* target)
560	:
561	BDragger(BRect(0, 0, 7, 7), target, B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM),
562	fTarget(target)
563{
564}
565
566
567void
568SysInfoDragger::MessageReceived(BMessage* message)
569{
570	switch (message->what) {
571		case _SHOW_DRAG_HANDLES_:
572			if (fTarget != NULL)
573				fTarget->Invalidate();
574		default:
575			BDragger::MessageReceived(message);
576			break;
577	}
578}
579
580
581//	#pragma mark - SysInfoView
582
583
584SysInfoView::SysInfoView()
585	:
586	BView("AboutSystem", B_WILL_DRAW | B_PULSE_NEEDED),
587	fVersionLabelView(NULL),
588	fVersionInfoView(NULL),
589	fCPULabelView(NULL),
590	fCPUInfoView(NULL),
591	fMemSizeView(NULL),
592	fMemUsageView(NULL),
593	fKernelDateTimeView(NULL),
594	fUptimeView(NULL),
595	fDragger(NULL),
596	fCachedBaseWidth(kSysInfoMinWidth),
597	fCachedMinWidth(kSysInfoMinWidth),
598	fCachedBaseHeight(kSysInfoMinHeight),
599	fCachedMinHeight(kSysInfoMinHeight)
600{
601	// Begin construction of system information controls.
602	system_info sysInfo;
603	get_system_info(&sysInfo);
604
605	// Create all the various labels for system infomation.
606
607	// OS Version / ABI
608	fVersionLabelView = _CreateLabel("oslabel", _GetOSVersion());
609	fVersionInfoView = _CreateSubtext("ostext", _GetABIVersion());
610
611	// CPU count, type and clock speed
612	fCPULabelView = _CreateLabel("cpulabel", _GetCPUCount(&sysInfo));
613	fCPUInfoView = _CreateSubtext("cputext", _GetCPUInfo());
614
615	// Memory size and usage
616	fMemSizeView = _CreateLabel("memlabel", _GetRamSize(&sysInfo));
617	fMemUsageView = _CreateSubtext("ramusagetext", _GetRamUsage(&sysInfo));
618
619	// Kernel build time/date
620	BStringView* kernelLabel = _CreateLabel("kernellabel", B_TRANSLATE("Kernel:"));
621	fKernelDateTimeView = _CreateSubtext("kerneltext", _GetKernelDateTime(&sysInfo));
622
623	// Uptime
624	BStringView* uptimeLabel = _CreateLabel("uptimelabel", B_TRANSLATE("Time running:"));
625	fUptimeView = new BTextView("uptimetext");
626	fUptimeView->SetText(_GetUptime());
627	_UpdateText(fUptimeView);
628
629	// Now comes the layout
630
631	const float offset = be_control_look->DefaultLabelSpacing();
632	const float inset = offset;
633
634	SetLayout(new BGroupLayout(B_VERTICAL, 0));
635	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
636		// Version:
637		.Add(fVersionLabelView)
638		.Add(fVersionInfoView)
639		.AddStrut(offset)
640		// Processors:
641		.Add(fCPULabelView)
642		.Add(fCPUInfoView)
643		.AddStrut(offset)
644		// Memory:
645		.Add(fMemSizeView)
646		.Add(fMemUsageView)
647		.AddStrut(offset)
648		// Kernel:
649		.Add(kernelLabel)
650		.Add(fKernelDateTimeView)
651		.AddStrut(offset)
652		// Time running:
653		.Add(uptimeLabel)
654		.Add(fUptimeView)
655		.AddGlue()
656		.SetInsets(inset)
657		.End();
658
659	_CreateDragger();
660}
661
662
663SysInfoView::~SysInfoView()
664{
665}
666
667
668status_t
669SysInfoView::Archive(BMessage* archive, bool deep) const
670{
671	// DO NOT record inherited class members
672	status_t result = B_OK;
673
674	// record app signature for replicant add-on loading
675	if (result == B_OK)
676		result = archive->AddString("add_on", kSignature);
677
678	// record class last
679	if (result == B_OK)
680		result = archive->AddString("class", "SysInfoView");
681
682	return result;
683}
684
685
686BArchivable*
687SysInfoView::Instantiate(BMessage* archive)
688{
689	if (!validate_instantiation(archive, "SysInfoView"))
690		return NULL;
691
692	return new SysInfoView();
693}
694
695
696void
697SysInfoView::AttachedToWindow()
698{
699	BView::AttachedToWindow();
700
701	Window()->SetPulseRate(500000);
702	DoLayout();
703
704	if (_OnDesktop()) {
705		// if we are a replicant the parent view doesn't do this for us
706		CacheInitialSize();
707		// add extra height for dragger: fixed, and insets: font-dependent
708		float draggerHeight = fDragger->Bounds().Height() + kDraggerMargin * 2;
709		float insets = be_control_look->DefaultLabelSpacing() * 2;
710		ResizeTo(fCachedMinWidth, fCachedMinHeight + draggerHeight + insets);
711	}
712}
713
714
715void
716SysInfoView::AllAttached()
717{
718	BView::AllAttached();
719
720	if (_OnDesktop())
721		fDesktopTextColor = _DesktopTextColor();
722
723	// Update colors here to override system colors for replicant,
724	// this works when the view is in AboutView too.
725	_AdjustColors();
726}
727
728
729void
730SysInfoView::CacheInitialSize()
731{
732	fCachedBaseWidth = _BaseWidth();
733	float insets = be_control_look->DefaultLabelSpacing() * 2;
734
735	// increase min width based on some potentially wide string views
736	fCachedMinWidth = ceilf(std::max(fCachedBaseWidth,
737		fVersionLabelView->StringWidth(fVersionLabelView->Text()) + insets));
738	fCachedMinWidth = ceilf(std::max(fCachedBaseWidth,
739		fCPUInfoView->StringWidth(fCPUInfoView->Text()) + insets));
740	fCachedMinWidth = ceilf(std::max(fCachedBaseWidth,
741		fMemSizeView->StringWidth(fMemSizeView->Text()) + insets));
742
743	// width is fixed, height can grow in Pulse()
744	fCachedBaseHeight = _BaseHeight();
745
746	// determine initial line count using current font
747	float lineCount = ceilf(be_plain_font->StringWidth(fUptimeView->Text())
748		/ (fCachedMinWidth - insets));
749	float uptimeHeight = fUptimeView->LineHeight(0) * lineCount;
750	fCachedMinHeight = fCachedBaseHeight + uptimeHeight;
751
752	// set view limits
753	SetExplicitMinSize(BSize(fCachedMinWidth, B_SIZE_UNSET));
754	SetExplicitMaxSize(BSize(fCachedMinWidth, fCachedMinHeight));
755	fUptimeView->SetExplicitMaxSize(BSize(fCachedMinWidth - insets, uptimeHeight));
756}
757
758
759void
760SysInfoView::Draw(BRect updateRect)
761{
762	BView::Draw(updateRect);
763
764	// stroke a line around the view
765	if (_OnDesktop() && fDragger != NULL && fDragger->AreDraggersDrawn())
766		StrokeRect(Bounds());
767}
768
769
770void
771SysInfoView::MessageReceived(BMessage* message)
772{
773	switch (message->what) {
774		case B_COLORS_UPDATED:
775		{
776			if (_OnDesktop())
777				break;
778
779			if (message->HasColor(ui_color_name(B_PANEL_TEXT_COLOR))) {
780				_AdjustTextColors();
781				Invalidate();
782			}
783
784			break;
785		}
786
787		case B_WORKSPACE_ACTIVATED:
788		{
789			if (!_OnDesktop())
790				break;
791
792			bool active;
793			int32 workspace;
794			if (message->FindBool("active", &active) == B_OK && active
795				&& message->FindInt32("workspace", &workspace) == B_OK) {
796				BLayout* layout = GetLayout();
797				int32 itemCount = layout->CountItems() - 2;
798					// leave out dragger and uptime
799
800				fDesktopTextColor = _DesktopTextColor(workspace);
801				SetHighColor(fDesktopTextColor);
802
803				for (int32 index = 0; index < itemCount; index++) {
804					BView* view = layout->ItemAt(index)->View();
805					if (view == NULL)
806						continue;
807
808					view->SetDrawingMode(B_OP_ALPHA);
809					view->SetHighColor(fDesktopTextColor);
810				}
811
812				fUptimeView->SetDrawingMode(B_OP_ALPHA);
813				fUptimeView->SetFontAndColor(NULL, 0, &fDesktopTextColor);
814
815				Invalidate();
816			}
817
818			break;
819		}
820
821		default:
822			BView::MessageReceived(message);
823			break;
824	}
825}
826
827
828void
829SysInfoView::Pulse()
830{
831	system_info sysInfo;
832	get_system_info(&sysInfo);
833
834	fMemUsageView->SetText(_GetRamUsage(&sysInfo));
835	fUptimeView->SetText(_GetUptime());
836
837	float newHeight = fCachedBaseHeight + _UptimeHeight();
838	_ResizeBy(0, newHeight - fCachedMinHeight);
839	fCachedMinHeight = newHeight;
840
841	SetExplicitMinSize(BSize(fCachedMinWidth, B_SIZE_UNSET));
842	SetExplicitMaxSize(BSize(fCachedMinWidth, fCachedMinHeight));
843}
844
845
846void
847SysInfoView::_AdjustColors()
848{
849	if (_OnDesktop()) {
850		// SetColor
851		SetFlags(Flags() | B_TRANSPARENT_BACKGROUND);
852		SetDrawingMode(B_OP_ALPHA);
853
854		SetViewColor(B_TRANSPARENT_COLOR);
855		SetLowColor(B_TRANSPARENT_COLOR);
856		SetHighColor(fDesktopTextColor);
857	} else {
858		// SetUIColor
859		SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
860		SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
861		SetHighUIColor(B_PANEL_TEXT_COLOR);
862	}
863
864	_AdjustTextColors();
865	Invalidate();
866}
867
868
869void
870SysInfoView::_AdjustTextColors() const
871{
872	BLayout* layout = GetLayout();
873	int32 itemCount = layout->CountItems() - 2;
874		// leave out dragger and uptime
875
876	if (_OnDesktop()) {
877		// SetColor
878		for (int32 index = 0; index < itemCount; index++) {
879			BView* view = layout->ItemAt(index)->View();
880			if (view == NULL)
881				continue;
882
883			view->SetFlags(view->Flags() | B_TRANSPARENT_BACKGROUND);
884			view->SetDrawingMode(B_OP_ALPHA);
885
886			view->SetViewColor(B_TRANSPARENT_COLOR);
887			view->SetLowColor(blend_color(B_TRANSPARENT_COLOR,
888				fDesktopTextColor, 192));
889			view->SetHighColor(fDesktopTextColor);
890		}
891
892		fUptimeView->SetFlags(fUptimeView->Flags() | B_TRANSPARENT_BACKGROUND);
893		fUptimeView->SetDrawingMode(B_OP_ALPHA);
894
895		fUptimeView->SetViewColor(B_TRANSPARENT_COLOR);
896		fUptimeView->SetLowColor(blend_color(B_TRANSPARENT_COLOR,
897			fDesktopTextColor, 192));
898		fUptimeView->SetFontAndColor(NULL, 0, &fDesktopTextColor);
899	} else {
900		// SetUIColor
901		for (int32 index = 0; index < itemCount; index++) {
902			BView* view = layout->ItemAt(index)->View();
903			if (view == NULL)
904				continue;
905
906			view->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
907			view->SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
908			view->SetHighUIColor(B_PANEL_TEXT_COLOR);
909		}
910
911		fUptimeView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
912		fUptimeView->SetLowUIColor(B_PANEL_BACKGROUND_COLOR);
913		rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
914		fUptimeView->SetFontAndColor(NULL, 0, &textColor);
915	}
916}
917
918
919rgb_color
920SysInfoView::_DesktopTextColor(int32 workspace) const
921{
922	// set text color to black or white depending on desktop background color
923	rgb_color textColor;
924	BScreen screen(Window());
925	if (workspace < 0)
926		workspace = current_workspace();
927
928	rgb_color viewColor = screen.DesktopColor(workspace);
929	textColor.blue = textColor.green = textColor.red = viewColor.IsLight() ? 0 : 255;
930	textColor.alpha = 255;
931
932	return textColor;
933}
934
935
936bool
937SysInfoView::_OnDesktop() const
938{
939	return Window() != NULL
940		&& Window()->Look() == kDesktopWindowLook
941		&& Window()->Feel() == kDesktopWindowFeel;
942}
943
944
945void
946SysInfoView::_ResizeBy(float widthChange, float heightChange)
947{
948	if (!_OnDesktop() || (widthChange == 0 && heightChange == 0))
949		return;
950
951	ResizeBy(widthChange, heightChange);
952	MoveBy(-widthChange, -heightChange);
953}
954
955
956void
957SysInfoView::_ResizeTo(float width, float height)
958{
959	_ResizeBy(width - Bounds().Width(), height - Bounds().Height());
960}
961
962
963BStringView*
964SysInfoView::_CreateLabel(const char* name, const char* text)
965{
966	BStringView* label = new BStringView(name, text);
967	_UpdateLabel(label);
968
969	return label;
970}
971
972
973void
974SysInfoView::_UpdateLabel(BStringView* label)
975{
976	label->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
977		B_ALIGN_VERTICAL_UNSET));
978	label->SetFont(be_bold_font, B_FONT_FAMILY_AND_STYLE);
979}
980
981
982BStringView*
983SysInfoView::_CreateSubtext(const char* name, const char* text)
984{
985	BStringView* subtext = new BStringView(name, text);
986	_UpdateSubtext(subtext);
987
988	return subtext;
989}
990
991
992void
993SysInfoView::_UpdateSubtext(BStringView* subtext)
994{
995	subtext->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT,
996		B_ALIGN_VERTICAL_UNSET));
997	subtext->SetFont(be_plain_font, B_FONT_FAMILY_AND_STYLE);
998}
999
1000
1001void
1002SysInfoView::_UpdateText(BTextView* textView)
1003{
1004	textView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
1005	textView->SetFontAndColor(be_plain_font, B_FONT_FAMILY_AND_STYLE);
1006	textView->SetColorSpace(B_RGBA32);
1007	textView->MakeResizable(false);
1008	textView->MakeEditable(false);
1009	textView->MakeSelectable(false);
1010	textView->SetWordWrap(true);
1011	textView->SetDoesUndo(false);
1012	textView->SetInsets(0, 0, 0, 0);
1013}
1014
1015
1016void
1017SysInfoView::_CreateDragger()
1018{
1019	// create replicant dragger and add it as the new child 0
1020	fDragger = new SysInfoDragger(this);
1021	BPopUpMenu* popUp = new BPopUpMenu("Shelf", false, false, B_ITEMS_IN_COLUMN);
1022	popUp->AddItem(new BMenuItem(B_TRANSLATE("Remove replicant"),
1023		new BMessage(kDeleteReplicant)));
1024	fDragger->SetPopUp(popUp);
1025	AddChild(fDragger, ChildAt(0));
1026}
1027
1028
1029float
1030SysInfoView::_BaseWidth()
1031{
1032	// based on font size
1033	return be_plain_font->StringWidth("M") * 24;
1034}
1035
1036
1037float
1038SysInfoView::_BaseHeight()
1039{
1040	// based on line heights
1041	font_height plainFH;
1042	be_plain_font->GetHeight(&plainFH);
1043	font_height boldFH;
1044	be_bold_font->GetHeight(&boldFH);
1045
1046	return ceilf(((boldFH.ascent + boldFH.descent) * kLabelCount
1047		+ (plainFH.ascent + plainFH.descent) * kSubtextCount
1048		+ be_control_look->DefaultLabelSpacing() * kLabelCount));
1049}
1050
1051
1052BString
1053SysInfoView::_GetOSVersion()
1054{
1055	BString revision;
1056	// add system revision to os version
1057	const char* hrev = __get_haiku_revision();
1058	if (hrev != NULL)
1059		revision.SetToFormat(B_TRANSLATE_COMMENT("Version: %s",
1060			"Version: R1 or hrev99999"), hrev);
1061	else
1062		revision = B_TRANSLATE("Version:");
1063
1064	return revision;
1065}
1066
1067
1068BString
1069SysInfoView::_GetABIVersion()
1070{
1071	BString abiVersion;
1072
1073	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
1074	BPath path;
1075	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
1076		path.Append("libbe.so");
1077
1078		BAppFileInfo appFileInfo;
1079		version_info versionInfo;
1080		BFile file;
1081		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
1082			&& appFileInfo.SetTo(&file) == B_OK
1083			&& appFileInfo.GetVersionInfo(&versionInfo,
1084				B_APP_VERSION_KIND) == B_OK
1085			&& versionInfo.short_info[0] != '\0')
1086			abiVersion = versionInfo.short_info;
1087	}
1088
1089	if (abiVersion.IsEmpty())
1090		abiVersion = B_TRANSLATE("Unknown");
1091
1092	abiVersion << " (" << B_HAIKU_ABI_NAME << ")";
1093
1094	return abiVersion;
1095}
1096
1097
1098BString
1099SysInfoView::_GetCPUCount(system_info* sysInfo)
1100{
1101	static BStringFormat format(B_TRANSLATE_COMMENT(
1102		"{0, plural, one{Processor:} other{# Processors:}}",
1103		"\"Processor:\" or \"2 Processors:\""));
1104
1105	BString processorLabel;
1106	format.Format(processorLabel, sysInfo->cpu_count);
1107	return processorLabel;
1108}
1109
1110
1111BString
1112SysInfoView::_GetCPUInfo()
1113{
1114	uint32 topologyNodeCount = 0;
1115	cpu_topology_node_info* topology = NULL;
1116
1117	get_cpu_topology_info(NULL, &topologyNodeCount);
1118	if (topologyNodeCount != 0)
1119		topology = new cpu_topology_node_info[topologyNodeCount];
1120	get_cpu_topology_info(topology, &topologyNodeCount);
1121
1122	enum cpu_platform platform = B_CPU_UNKNOWN;
1123	enum cpu_vendor cpuVendor = B_CPU_VENDOR_UNKNOWN;
1124	uint32 cpuModel = 0;
1125
1126	for (uint32 i = 0; i < topologyNodeCount; i++) {
1127		switch (topology[i].type) {
1128			case B_TOPOLOGY_ROOT:
1129				platform = topology[i].data.root.platform;
1130				break;
1131
1132			case B_TOPOLOGY_PACKAGE:
1133				cpuVendor = topology[i].data.package.vendor;
1134				break;
1135
1136			case B_TOPOLOGY_CORE:
1137				cpuModel = topology[i].data.core.model;
1138				break;
1139
1140			default:
1141				break;
1142		}
1143	}
1144
1145	delete[] topology;
1146
1147	BString cpuType;
1148	cpuType << get_cpu_vendor_string(cpuVendor) << " "
1149		<< get_cpu_model_string(platform, cpuVendor, cpuModel)
1150		<< " @ " << _GetCPUFrequency();
1151
1152	return cpuType;
1153}
1154
1155
1156BString
1157SysInfoView::_GetCPUFrequency()
1158{
1159	BString clockSpeed;
1160
1161	int32 frequency = get_rounded_cpu_speed();
1162	if (frequency < 1000) {
1163		clockSpeed.SetToFormat(B_TRANSLATE_COMMENT("%ld MHz",
1164			"750 Mhz (CPU clock speed)"), frequency);
1165	}
1166	else {
1167		clockSpeed.SetToFormat(B_TRANSLATE_COMMENT("%.2f GHz",
1168			"3.49 Ghz (CPU clock speed)"), frequency / 1000.0f);
1169	}
1170
1171	return clockSpeed;
1172}
1173
1174
1175BString
1176SysInfoView::_GetRamSize(system_info* sysInfo)
1177{
1178	BString ramSize;
1179	ramSize.SetToFormat(B_TRANSLATE_COMMENT("%d MiB Memory:",
1180		"2048 MiB Memory:"), max_and_ignored_pages(sysInfo));
1181
1182	return ramSize;
1183}
1184
1185
1186BString
1187SysInfoView::_GetRamUsage(system_info* sysInfo)
1188{
1189	BString ramUsage;
1190	BString data;
1191	double usedMemoryPercent = double(sysInfo->used_pages) / sysInfo->max_pages;
1192	status_t status = fNumberFormat.FormatPercent(data, usedMemoryPercent);
1193
1194	if (status == B_OK) {
1195		ramUsage.SetToFormat(B_TRANSLATE_COMMENT("%d MiB used (%s)",
1196			"326 MiB used (16%)"), used_pages(sysInfo), data.String());
1197	} else {
1198		ramUsage.SetToFormat(B_TRANSLATE_COMMENT("%d MiB used (%d%%)",
1199			"326 MiB used (16%)"), used_pages(sysInfo), (int)(100 * usedMemoryPercent));
1200	}
1201
1202	return ramUsage;
1203}
1204
1205
1206BString
1207SysInfoView::_GetKernelDateTime(system_info* sysInfo)
1208{
1209	BString kernelDateTime;
1210
1211	BString buildDateTime;
1212	buildDateTime << sysInfo->kernel_build_date << " " << sysInfo->kernel_build_time;
1213
1214	time_t buildDateTimeStamp = parsedate(buildDateTime, -1);
1215
1216	if (buildDateTimeStamp > 0) {
1217		if (BDateTimeFormat().Format(kernelDateTime, buildDateTimeStamp,
1218			B_LONG_DATE_FORMAT, B_MEDIUM_TIME_FORMAT) != B_OK)
1219			kernelDateTime.SetTo(buildDateTime);
1220	} else
1221		kernelDateTime.SetTo(buildDateTime);
1222
1223	return kernelDateTime;
1224}
1225
1226
1227BString
1228SysInfoView::_GetUptime()
1229{
1230	BDurationFormat formatter;
1231	BString uptimeText;
1232
1233	bigtime_t uptime = system_time();
1234	bigtime_t now = (bigtime_t)time(NULL) * 1000000;
1235	formatter.Format(uptimeText, now - uptime, now);
1236
1237	return uptimeText;
1238}
1239
1240
1241float
1242SysInfoView::_UptimeHeight()
1243{
1244	return fUptimeView->LineHeight(0) * fUptimeView->CountLines();
1245}
1246
1247
1248//	#pragma mark - AboutView
1249
1250
1251AboutView::AboutView()
1252	:
1253	BView("aboutview", B_WILL_DRAW | B_PULSE_NEEDED),
1254	fLogoView(NULL),
1255	fSysInfoView(NULL),
1256	fCreditsView(NULL),
1257	fLastActionTime(system_time()),
1258	fScrollRunner(NULL),
1259	fCachedMinWidth(kSysInfoMinWidth),
1260	fCachedMinHeight(kSysInfoMinHeight)
1261{
1262	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
1263
1264	// Assign the colors, sadly this does not respect live color updates
1265	fTextColor = ui_color(B_DOCUMENT_TEXT_COLOR);
1266	fLinkColor = ui_color(B_LINK_TEXT_COLOR);
1267	fHaikuOrangeColor = mix_color(fTextColor, kIdealHaikuOrange, 191);
1268	fHaikuGreenColor = mix_color(fTextColor, kIdealHaikuGreen, 191);
1269	fHaikuYellowColor = mix_color(fTextColor, kIdealHaikuYellow, 191);
1270	fBeOSRedColor = mix_color(fTextColor, kIdealBeOSRed, 191);
1271	fBeOSBlueColor = mix_color(fTextColor, kIdealBeOSBlue, 191);
1272
1273	SetLayout(new BGroupLayout(B_HORIZONTAL, 0));
1274	BLayoutBuilder::Group<>((BGroupLayout*)GetLayout())
1275		.AddGroup(B_VERTICAL, 0)
1276			.Add(_CreateLogoView())
1277			.Add(_CreateSysInfoView())
1278			.AddGlue()
1279			.End()
1280		.Add(_CreateCreditsView())
1281		.End();
1282}
1283
1284
1285AboutView::~AboutView()
1286{
1287	for (PackageCreditMap::iterator it = fPackageCredits.begin();
1288		it != fPackageCredits.end(); it++) {
1289
1290		delete it->second;
1291	}
1292
1293	delete fScrollRunner;
1294	delete fCreditsView;
1295	delete fSysInfoView;
1296	delete fLogoView;
1297}
1298
1299
1300void
1301AboutView::AttachedToWindow()
1302{
1303	BView::AttachedToWindow();
1304
1305	fSysInfoView->CacheInitialSize();
1306
1307	float insets = be_control_look->DefaultLabelSpacing() * 2;
1308	float infoWidth = fSysInfoView->MinWidth() + insets;
1309	float creditsWidth = roundf(infoWidth * 1.25f);
1310	fCachedMinWidth = std::max(infoWidth + creditsWidth,
1311		fCachedMinWidth);
1312		// set once
1313	float logoViewHeight = fLogoView->Bounds().Height();
1314	float sysInfoViewHeight = fSysInfoView->MinHeight() + insets;
1315	fCachedMinHeight = std::max(logoViewHeight + sysInfoViewHeight,
1316		fCachedMinHeight);
1317		// updated when height changes in pulse
1318	fCreditsView->SetExplicitMinSize(BSize(creditsWidth, fCachedMinHeight));
1319		// set credits min height to logo height + sys-info height
1320
1321	SetEventMask(B_POINTER_EVENTS);
1322	DoLayout();
1323}
1324
1325
1326void
1327AboutView::MouseDown(BPoint where)
1328{
1329	BRect rect(92, 26, 105, 31);
1330	if (rect.Contains(where))
1331		BMessenger(this).SendMessage('eegg');
1332
1333	if (Bounds().Contains(where)) {
1334		fLastActionTime = system_time();
1335		delete fScrollRunner;
1336		fScrollRunner = NULL;
1337	}
1338}
1339
1340
1341void
1342AboutView::Pulse()
1343{
1344	// sys-info handles height because it may be a replicant
1345	float insets = be_control_look->DefaultLabelSpacing() * 2;
1346	float logoViewHeight = fLogoView->Bounds().Height();
1347	float sysInfoViewHeight = fSysInfoView->MinHeight() + insets;
1348	float newHeight = logoViewHeight + sysInfoViewHeight;
1349	if (newHeight != fCachedMinHeight) {
1350		fCreditsView->SetExplicitMinSize(BSize(
1351			fCachedMinWidth - (fSysInfoView->MinWidth() + insets), newHeight));
1352		fCachedMinHeight = newHeight;
1353	}
1354
1355	if (fScrollRunner == NULL && system_time() > fLastActionTime + 10000000)
1356		_CreateScrollRunner();
1357}
1358
1359
1360void
1361AboutView::MessageReceived(BMessage* message)
1362{
1363	switch (message->what) {
1364		case kMsgScrollCreditsView:
1365		{
1366			BScrollBar* scrollBar = fCreditsView->ScrollBar(B_VERTICAL);
1367			if (scrollBar == NULL)
1368				break;
1369			float min;
1370			float max;
1371			scrollBar->GetRange(&min, &max);
1372			if (scrollBar->Value() < max)
1373				fCreditsView->ScrollBy(0, 1);
1374
1375			break;
1376		}
1377
1378		case 'eegg':
1379		{
1380			printf("Easter egg\n");
1381			PickRandomHaiku();
1382			break;
1383		}
1384
1385		default:
1386			BView::MessageReceived(message);
1387			break;
1388	}
1389}
1390
1391
1392void
1393AboutView::AddCopyrightEntry(const char* name, const char* text,
1394	const char* url)
1395{
1396	AddCopyrightEntry(name, text, StringVector(), StringVector(), url);
1397}
1398
1399
1400void
1401AboutView::AddCopyrightEntry(const char* name, const char* text,
1402	const StringVector& licenses, const StringVector& sources,
1403	const char* url)
1404{
1405	BFont font(be_bold_font);
1406	//font.SetSize(be_bold_font->Size());
1407	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1408
1409	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuYellowColor);
1410	fCreditsView->Insert(name);
1411	fCreditsView->Insert("\n");
1412	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1413	fCreditsView->Insert(text);
1414	fCreditsView->Insert("\n");
1415
1416	if (licenses.CountStrings() > 0) {
1417		if (licenses.CountStrings() > 1)
1418			fCreditsView->Insert(B_TRANSLATE("Licenses: "));
1419		else
1420			fCreditsView->Insert(B_TRANSLATE("License: "));
1421
1422		for (int32 i = 0; i < licenses.CountStrings(); i++) {
1423			const char* license = licenses.StringAt(i);
1424
1425			if (i > 0)
1426				fCreditsView->Insert(", ");
1427
1428			BString licenseName;
1429			BString licenseURL;
1430			parse_named_url(license, licenseName, licenseURL);
1431
1432			BPath licensePath;
1433			if (_GetLicensePath(licenseURL, licensePath) == B_OK) {
1434				fCreditsView->InsertHyperText(B_TRANSLATE_NOCOLLECT(licenseName),
1435					new OpenFileAction(licensePath.Path()));
1436			} else
1437				fCreditsView->Insert(licenseName);
1438		}
1439
1440		fCreditsView->Insert("\n");
1441	}
1442
1443	if (sources.CountStrings() > 0) {
1444		fCreditsView->Insert(B_TRANSLATE("Source Code: "));
1445
1446		for (int32 i = 0; i < sources.CountStrings(); i++) {
1447			const char* source = sources.StringAt(i);
1448
1449			if (i > 0)
1450				fCreditsView->Insert(", ");
1451
1452			BString urlName;
1453			BString urlAddress;
1454			parse_named_url(source, urlName, urlAddress);
1455
1456			fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
1457				&fLinkColor);
1458			fCreditsView->InsertHyperText(urlName,
1459				new URLAction(urlAddress));
1460		}
1461
1462		fCreditsView->Insert("\n");
1463	}
1464
1465	if (url) {
1466		BString urlName;
1467		BString urlAddress;
1468		parse_named_url(url, urlName, urlAddress);
1469
1470		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL,
1471			&fLinkColor);
1472		fCreditsView->InsertHyperText(urlName,
1473			new URLAction(urlAddress));
1474		fCreditsView->Insert("\n");
1475	}
1476	fCreditsView->Insert("\n");
1477}
1478
1479
1480void
1481AboutView::PickRandomHaiku()
1482{
1483	BPath path;
1484	if (find_directory(B_SYSTEM_DATA_DIRECTORY, &path) != B_OK)
1485		path = "/system/data";
1486	path.Append("fortunes");
1487	path.Append("Haiku");
1488
1489	BFile fortunes(path.Path(), B_READ_ONLY);
1490	struct stat st;
1491	if (fortunes.InitCheck() < B_OK)
1492		return;
1493	if (fortunes.GetStat(&st) < B_OK)
1494		return;
1495
1496	char* buff = (char*)malloc((size_t)st.st_size + 1);
1497	if (buff == NULL)
1498		return;
1499
1500	buff[(size_t)st.st_size] = '\0';
1501	BList haikuList;
1502	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
1503		char* p = buff;
1504		while (p && *p) {
1505			char* e = strchr(p, '%');
1506			BString* s = new BString(p, e ? (e - p) : -1);
1507			haikuList.AddItem(s);
1508			p = e;
1509			if (p && (*p == '%'))
1510				p++;
1511			if (p && (*p == '\n'))
1512				p++;
1513		}
1514	}
1515	free(buff);
1516
1517	if (haikuList.CountItems() < 1)
1518		return;
1519
1520	BString* s = (BString*)haikuList.ItemAt(rand() % haikuList.CountItems());
1521	BFont font(be_bold_font);
1522	font.SetSize(be_bold_font->Size());
1523	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1524	fCreditsView->SelectAll();
1525	fCreditsView->Delete();
1526	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fTextColor);
1527	fCreditsView->Insert(s->String());
1528	fCreditsView->Insert("\n");
1529	while ((s = (BString*)haikuList.RemoveItem((int32)0)))
1530		delete s;
1531}
1532
1533
1534void
1535AboutView::_CreateScrollRunner()
1536{
1537#if 0
1538	BMessage scroll(kMsgScrollCreditsView);
1539	fScrollRunner = new(std::nothrow) BMessageRunner(this, &scroll, 25000, -1);
1540#endif
1541}
1542
1543
1544LogoView*
1545AboutView::_CreateLogoView()
1546{
1547	fLogoView = new(std::nothrow) LogoView();
1548
1549	return fLogoView;
1550}
1551
1552
1553SysInfoView*
1554AboutView::_CreateSysInfoView()
1555{
1556	fSysInfoView = new(std::nothrow) SysInfoView();
1557
1558	return fSysInfoView;
1559}
1560
1561
1562CropView*
1563AboutView::_CreateCreditsView()
1564{
1565	// Begin construction of the credits view
1566	fCreditsView = new HyperTextView("credits");
1567	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS);
1568	fCreditsView->SetStylable(true);
1569	fCreditsView->MakeEditable(false);
1570	fCreditsView->SetWordWrap(true);
1571	fCreditsView->SetInsets(5, 5, 5, 5);
1572	fCreditsView->SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
1573
1574	BScrollView* creditsScroller = new BScrollView("creditsScroller",
1575		fCreditsView, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
1576		B_PLAIN_BORDER);
1577
1578	// Haiku copyright
1579	BFont font(be_bold_font);
1580	font.SetSize(font.Size() + 4);
1581
1582	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuGreenColor);
1583	fCreditsView->Insert("Haiku\n");
1584
1585	time_t time = ::time(NULL);
1586	struct tm* tm = localtime(&time);
1587	int32 year = tm->tm_year + 1900;
1588	if (year < 2008)
1589		year = 2008;
1590	BString text;
1591	text.SetToFormat(
1592		B_TRANSLATE(COPYRIGHT_STRING "2001-%" B_PRId32 " The Haiku project. "),
1593		year);
1594
1595	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1596	fCreditsView->Insert(text.String());
1597
1598	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1599	fCreditsView->Insert(B_TRANSLATE("The copyright to the Haiku code is "
1600		"property of Haiku, Inc. or of the respective authors where expressly "
1601		"noted in the source. Haiku" B_UTF8_REGISTERED
1602		" and the HAIKU logo" B_UTF8_REGISTERED
1603		" are registered trademarks of Haiku, Inc."
1604		"\n\n"));
1605
1606	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fLinkColor);
1607	fCreditsView->InsertHyperText(B_TRANSLATE("Visit the Haiku website"),
1608		new URLAction("https://www.haiku-os.org"));
1609	fCreditsView->Insert("\n");
1610	fCreditsView->InsertHyperText(B_TRANSLATE("Make a donation"),
1611		new URLAction("https://www.haiku-inc.org/donate"));
1612	fCreditsView->Insert("\n\n");
1613
1614	font.SetSize(be_bold_font->Size());
1615	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
1616
1617	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1618	fCreditsView->Insert(B_TRANSLATE("Current maintainers:\n"));
1619
1620	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1621	fCreditsView->Insert(kCurrentMaintainers);
1622
1623	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1624	fCreditsView->Insert(B_TRANSLATE("Past maintainers:\n"));
1625
1626	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1627	fCreditsView->Insert(kPastMaintainers);
1628
1629	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1630	fCreditsView->Insert(B_TRANSLATE("Website & marketing:\n"));
1631
1632	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1633	fCreditsView->Insert(kWebsiteTeam);
1634
1635	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1636	fCreditsView->Insert(B_TRANSLATE("Past website & marketing:\n"));
1637
1638	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1639	fCreditsView->Insert(kPastWebsiteTeam);
1640
1641	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1642	fCreditsView->Insert(B_TRANSLATE("Testing and bug triaging:\n"));
1643
1644	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1645	fCreditsView->Insert(kTestingTeam);
1646
1647	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1648	fCreditsView->Insert(B_TRANSLATE("Contributors:\n"));
1649
1650	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1651	fCreditsView->Insert(kContributors);
1652	fCreditsView->Insert(
1653		B_TRANSLATE("\n" B_UTF8_ELLIPSIS
1654			"and probably some more we forgot to mention (sorry!)"
1655			"\n\n"));
1656
1657	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1658	fCreditsView->Insert(B_TRANSLATE("Translations:\n"));
1659
1660	BLanguage* lang;
1661	BString langName;
1662
1663	BList sortedTranslations;
1664	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
1665		const Translation* translation = &kTranslations[i];
1666		sortedTranslations.AddItem((void*)translation);
1667	}
1668	sortedTranslations.SortItems(TranslationComparator);
1669
1670	for (uint32 i = 0; i < kNumberOfTranslations; i ++) {
1671		const Translation& translation
1672			= *(const Translation*)sortedTranslations.ItemAt(i);
1673
1674		langName.Truncate(0);
1675		if (BLocaleRoster::Default()->GetLanguage(translation.languageCode,
1676				&lang) == B_OK) {
1677			lang->GetName(langName);
1678			delete lang;
1679		} else {
1680			// We failed to get the localized readable name,
1681			// go with what we have.
1682			langName.Append(translation.languageCode);
1683		}
1684
1685		fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuGreenColor);
1686		fCreditsView->Insert("\n");
1687		fCreditsView->Insert(langName);
1688		fCreditsView->Insert("\n");
1689		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1690		fCreditsView->Insert(translation.names);
1691	}
1692
1693	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuOrangeColor);
1694	fCreditsView->Insert(B_TRANSLATE("\n\nSpecial thanks to:\n"));
1695
1696	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1697	BString beosCredits(B_TRANSLATE(
1698		"Be Inc. and its developer team, for having created BeOS!\n\n"));
1699	int32 beosOffset = beosCredits.FindFirst("BeOS");
1700	fCreditsView->Insert(beosCredits.String(),
1701		(beosOffset < 0) ? beosCredits.Length() : beosOffset);
1702	if (beosOffset > -1) {
1703		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fBeOSBlueColor);
1704		fCreditsView->Insert("B");
1705		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fBeOSRedColor);
1706		fCreditsView->Insert("e");
1707		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1708		beosCredits.Remove(0, beosOffset + 2);
1709		fCreditsView->Insert(beosCredits.String(), beosCredits.Length());
1710	}
1711	fCreditsView->Insert(
1712		B_TRANSLATE("Travis Geiselbrecht (and his NewOS kernel)\n"));
1713	fCreditsView->Insert(
1714		B_TRANSLATE("Michael Phipps (project founder)\n\n"));
1715	fCreditsView->Insert(
1716		B_TRANSLATE("The HaikuPorts team\n"));
1717	fCreditsView->Insert(
1718		B_TRANSLATE("The Haikuware team and their bounty program\n"));
1719	fCreditsView->Insert(
1720		B_TRANSLATE("The BeGeistert team\n"));
1721	fCreditsView->Insert(
1722		B_TRANSLATE("Google and their Google Summer of Code and Google Code In "
1723			"programs\n"));
1724	fCreditsView->Insert(
1725		B_TRANSLATE("The University of Auckland and Christof Lutteroth\n\n"));
1726	fCreditsView->Insert(
1727		B_TRANSLATE(B_UTF8_ELLIPSIS "and the many people making donations!\n\n"));
1728
1729	// copyrights for various projects we use
1730
1731	BPath mitPath;
1732	_GetLicensePath("MIT", mitPath);
1733	BPath lgplPath;
1734	_GetLicensePath("GNU LGPL v2.1", lgplPath);
1735
1736	font.SetSize(be_bold_font->Size() + 4);
1737	font.SetFace(B_BOLD_FACE);
1738	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &fHaikuGreenColor);
1739	fCreditsView->Insert(B_TRANSLATE("\nCopyrights\n\n"));
1740
1741	// Haiku license
1742	BString haikuLicense = B_TRANSLATE_COMMENT("The code that is unique to "
1743		"Haiku, especially the kernel and all code that applications may link "
1744		"against, is distributed under the terms of the <MIT license>. "
1745		"Some system libraries contain third party code distributed under the "
1746		"<LGPL license>. You can find the copyrights to third party code below."
1747		"\n\n", "<MIT license> and <LGPL license> aren't variables and can be "
1748		"translated. However, please, don't remove < and > as they're needed "
1749		"as placeholders for proper hypertext functionality.");
1750	int32 licensePart1 = haikuLicense.FindFirst("<");
1751	int32 licensePart2 = haikuLicense.FindFirst(">");
1752	int32 licensePart3 = haikuLicense.FindLast("<");
1753	int32 licensePart4 = haikuLicense.FindLast(">");
1754	BString part;
1755	haikuLicense.CopyInto(part, 0, licensePart1);
1756	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1757	fCreditsView->Insert(part);
1758
1759	part.Truncate(0);
1760	haikuLicense.CopyInto(part, licensePart1 + 1, licensePart2 - 1
1761		- licensePart1);
1762	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fLinkColor);
1763	fCreditsView->InsertHyperText(part, new OpenFileAction(mitPath.Path()));
1764
1765	part.Truncate(0);
1766	haikuLicense.CopyInto(part, licensePart2 + 1, licensePart3 - 1
1767		- licensePart2);
1768	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1769	fCreditsView->Insert(part);
1770
1771	part.Truncate(0);
1772	haikuLicense.CopyInto(part, licensePart3 + 1, licensePart4 - 1
1773		- licensePart3);
1774	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fLinkColor);
1775	fCreditsView->InsertHyperText(part, new OpenFileAction(lgplPath.Path()));
1776
1777	part.Truncate(0);
1778	haikuLicense.CopyInto(part, licensePart4 + 1, haikuLicense.Length() - 1
1779		- licensePart4);
1780	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &fTextColor);
1781	fCreditsView->Insert(part);
1782
1783	// GNU copyrights
1784	AddCopyrightEntry("The GNU Project",
1785		B_TRANSLATE("Contains software from the GNU Project, "
1786		"released under the GPL and LGPL licenses:\n"
1787		"GNU C Library, "
1788		"GNU coretools, diffutils, findutils, "
1789		"sharutils, gawk, bison, m4, make, "
1790		"wget, ncurses, termcap, "
1791		"Bourne Again Shell.\n"
1792		COPYRIGHT_STRING "The Free Software Foundation."),
1793		StringVector(kLGPLv21, kGPLv2, kGPLv3, NULL),
1794		StringVector(),
1795		"https://www.gnu.org");
1796
1797	// FreeBSD copyrights
1798	AddCopyrightEntry("The FreeBSD Project",
1799		B_TRANSLATE("Contains software from the FreeBSD Project, "
1800		"released under the BSD license:\n"
1801		"ftpd, ping, telnet, telnetd, traceroute\n"
1802		COPYRIGHT_STRING "1994-2008 The FreeBSD Project. "
1803		"All rights reserved."),
1804		StringVector(kBSDTwoClause, kBSDThreeClause, kBSDFourClause,
1805			NULL),
1806		StringVector(),
1807		"https://www.freebsd.org");
1808
1809	// FFmpeg copyrights
1810	_AddPackageCredit(PackageCredit("FFmpeg")
1811		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2000-2019 Fabrice "
1812			"Bellard, et al."))
1813		.SetLicenses(kLGPLv21, kLGPLv2, NULL)
1814		.SetURL("https://www.ffmpeg.org"));
1815
1816	// AGG copyrights
1817	_AddPackageCredit(PackageCredit("AntiGrain Geometry")
1818		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2006 Maxim "
1819			"Shemanarev (McSeem)."))
1820		.SetLicenses("Anti-Grain Geometry", kBSDThreeClause, NULL)
1821		.SetURL("http://www.antigrain.com"));
1822
1823	// FreeType copyrights
1824	_AddPackageCredit(PackageCredit("FreeType2")
1825		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1996-2002, 2006 "
1826			"David Turner, Robert Wilhelm and Werner Lemberg."),
1827			COPYRIGHT_STRING "2014 The FreeType Project. "
1828			"All rights reserved.",
1829			NULL)
1830		.SetLicense("FreeType")
1831		.SetURL("http://www.freetype.org"));
1832
1833	// Mesa3D (http://www.mesa3d.org) copyrights
1834	_AddPackageCredit(PackageCredit("Mesa")
1835		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2006 Brian Paul. "
1836			"Mesa3D Project. All rights reserved."))
1837		.SetLicense("MIT")
1838		.SetURL("http://www.mesa3d.org"));
1839
1840	// SGI's GLU implementation copyrights
1841	_AddPackageCredit(PackageCredit("GLU")
1842		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1991-2000 "
1843			"Silicon Graphics, Inc. All rights reserved."))
1844		.SetLicense("SGI Free B")
1845		.SetURL("http://www.sgi.com/products/software/opengl"));
1846
1847	// GLUT implementation copyrights
1848	_AddPackageCredit(PackageCredit("GLUT")
1849		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1994-1997 Mark Kilgard. "
1850			"All rights reserved."),
1851			COPYRIGHT_STRING "1997 Be Inc.",
1852			COPYRIGHT_STRING "1999 Jake Hamby.",
1853			NULL)
1854		.SetLicense("MIT")
1855		.SetURL("http://www.opengl.org/resources/libraries/glut"));
1856
1857	// OpenGroup & DEC (BRegion backend) copyright
1858	_AddPackageCredit(PackageCredit("BRegion backend (XFree86)")
1859		.SetCopyrights(COPYRIGHT_STRING "1987-1988, 1998 The Open Group.",
1860			B_TRANSLATE(COPYRIGHT_STRING "1987-1988 Digital Equipment "
1861			"Corporation, Maynard, Massachusetts.\n"
1862			"All rights reserved."),
1863			NULL)
1864		.SetLicenses("OpenGroup", "DEC", NULL)
1865		.SetURL("https://xfree86.org"));
1866
1867	// Bitstream Charter font
1868	_AddPackageCredit(PackageCredit("Bitstream Charter font")
1869		.SetCopyrights(COPYRIGHT_STRING "1989-1992 Bitstream Inc.,"
1870			"Cambridge, MA.",
1871			B_TRANSLATE("BITSTREAM CHARTER is a registered trademark of "
1872				"Bitstream Inc."),
1873			NULL)
1874		.SetLicense("Bitstream Charter")
1875		.SetURL("http://www.bitstream.com/"));
1876
1877	// Noto fonts copyright
1878	_AddPackageCredit(PackageCredit("Noto fonts")
1879		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING
1880			"2012-2016 Google Internationalization team."),
1881			NULL)
1882		.SetLicense("SIL Open Font Licence v1.1")
1883		.SetURL("http://www.google.com/get/noto/"));
1884
1885	// expat copyrights
1886	_AddPackageCredit(PackageCredit("expat")
1887		.SetCopyrights(B_TRANSLATE(COPYRIGHT_STRING "1998-2000 Thai "
1888			"Open Source Software Center Ltd and Clark Cooper."),
1889			B_TRANSLATE(COPYRIGHT_STRING "2001-2003 Expat maintainers."),
1890			NULL)
1891		.SetLicense("Expat")
1892		.SetURL("http://expat.sourceforge.net"));
1893
1894	// zlib copyrights
1895	_AddPackageCredit(PackageCredit("zlib")
1896		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2004 Jean-loup "
1897			"Gailly and Mark Adler."))
1898		.SetLicense("Zlib")
1899		.SetURL("http://www.zlib.net"));
1900
1901	// zip copyrights
1902	_AddPackageCredit(PackageCredit("Info-ZIP")
1903		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1990-2002 Info-ZIP. "
1904			"All rights reserved."))
1905		.SetLicense("Info-ZIP")
1906		.SetURL("http://www.info-zip.org"));
1907
1908	// bzip2 copyrights
1909	_AddPackageCredit(PackageCredit("bzip2")
1910		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-2005 Julian R "
1911			"Seward. All rights reserved."))
1912		.SetLicense(kBSDFourClause)
1913		.SetURL("http://bzip.org"));
1914
1915	// OpenEXR copyrights
1916	_AddPackageCredit(PackageCredit("OpenEXR")
1917		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2014 Industrial "
1918			"Light & Magic, a division of Lucas Digital Ltd. LLC."))
1919		.SetLicense(kBSDThreeClause)
1920		.SetURL("http://www.openexr.com"));
1921
1922	// acpica copyrights
1923	_AddPackageCredit(PackageCredit("ACPI Component Architecture (ACPICA)")
1924		.SetCopyright(COPYRIGHT_STRING "1999-2018 Intel Corp.")
1925		.SetLicense("Intel (ACPICA)")
1926		.SetURL("https://www.acpica.org"));
1927
1928	// libpng copyrights
1929	_AddPackageCredit(PackageCredit("libpng")
1930		.SetCopyright(COPYRIGHT_STRING "1995-2017 libpng authors")
1931		.SetLicense("LibPNG")
1932		.SetURL("http://www.libpng.org"));
1933
1934	// libjpeg copyrights
1935	_AddPackageCredit(PackageCredit("libjpeg")
1936		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1994-2009, Thomas G. "
1937			"Lane, Guido Vollbeding. This software is based in part on the "
1938			"work of the Independent JPEG Group."))
1939		.SetLicense("LibJPEG")
1940		.SetURL("http://www.ijg.org"));
1941
1942	// libprint copyrights
1943	_AddPackageCredit(PackageCredit("libprint")
1944		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2000 Y.Takagi. "
1945			"All rights reserved.")));
1946			// TODO: License!
1947
1948	// cortex copyrights
1949	_AddPackageCredit(PackageCredit("Cortex")
1950		.SetCopyright(COPYRIGHT_STRING "1999-2000 Eric Moon.")
1951		.SetLicense(kBSDThreeClause)
1952		.SetURL("http://cortex.sourceforge.net/documentation"));
1953
1954	// FluidSynth copyrights
1955	_AddPackageCredit(PackageCredit("FluidSynth")
1956		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003 Peter Hanappe "
1957			"and others."))
1958		.SetLicense(kLGPLv2)
1959		.SetURL("http://www.fluidsynth.org"));
1960
1961	// Xiph.org Foundation copyrights
1962	_AddPackageCredit(PackageCredit("Xiph.org Foundation")
1963		.SetCopyrights("libvorbis, libogg, libtheora, libspeex",
1964			B_TRANSLATE(COPYRIGHT_STRING "1994-2008 Xiph.Org. "
1965			"All rights reserved."), NULL)
1966		.SetLicense(kBSDThreeClause)
1967		.SetURL("http://www.xiph.org"));
1968
1969	// Matroska
1970	_AddPackageCredit(PackageCredit("libmatroska")
1971		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2003 Steve Lhomme. "
1972			"All rights reserved."))
1973		.SetLicense(kLGPLv21)
1974		.SetURL("http://www.matroska.org"));
1975
1976	// BColorQuantizer (originally CQuantizer code)
1977	_AddPackageCredit(PackageCredit("CQuantizer")
1978		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1996-1997 Jeff Prosise. "
1979			"All rights reserved."))
1980		.SetLicense("CQuantizer")
1981		.SetURL("http://www.xdp.it"));
1982
1983	// MAPM (Mike's Arbitrary Precision Math Library) used by DeskCalc
1984	_AddPackageCredit(PackageCredit("MAPM")
1985		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1999-2007 Michael C. "
1986			"Ring. All rights reserved."))
1987		.SetLicense("MAPM")
1988		.SetURL("http://tc.umn.edu/~ringx004"));
1989
1990	// MkDepend 1.7 copyright (Makefile dependency generator)
1991	_AddPackageCredit(PackageCredit("MkDepend")
1992		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995-2001 Lars D��ning. "
1993			"All rights reserved."))
1994		.SetLicense("MIT")
1995		.SetURL("http://bearnip.com/lars/be"));
1996
1997	// libhttpd copyright (used as Poorman backend)
1998	_AddPackageCredit(PackageCredit("libhttpd")
1999		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "1995, 1998-2001 "
2000			"Jef Poskanzer. All rights reserved."))
2001		.SetLicense(kBSDTwoClause)
2002		.SetURL("http://www.acme.com/software/thttpd/"));
2003
2004#ifdef __i386__
2005	// Udis86 copyrights
2006	_AddPackageCredit(PackageCredit("Udis86")
2007		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2002-2004 "
2008			"Vivek Mohan. All rights reserved."))
2009		.SetLicense(kBSDTwoClause)
2010		.SetURL("http://udis86.sourceforge.net"));
2011
2012	// Intel PRO/Wireless 2100 & 2200BG firmwares
2013	_AddPackageCredit(PackageCredit("Intel PRO/Wireless 2100 & 2200BG firmwares")
2014		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2003-2006 "
2015			"Intel Corporation. All rights reserved."))
2016		.SetLicense(kIntel2xxxFirmware)
2017		.SetURL("http://www.intellinuxwireless.org/"));
2018
2019	// Intel wireless firmwares
2020	_AddPackageCredit(
2021		PackageCredit("Intel PRO/Wireless network adapter firmwares")
2022		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2015 "
2023			"Intel Corporation. All rights reserved."))
2024		.SetLicense(kIntelFirmware)
2025		.SetURL("http://www.intellinuxwireless.org/"));
2026
2027	// Marvell 88w8363
2028	_AddPackageCredit(PackageCredit("Marvell 88w8363")
2029		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007-2009 "
2030			"Marvell Semiconductor, Inc. All rights reserved."))
2031		.SetLicense(kMarvellFirmware)
2032		.SetURL("http://www.marvell.com/"));
2033
2034	// Ralink Firmware RT2501/RT2561/RT2661
2035	_AddPackageCredit(PackageCredit("Ralink Firmware RT2501/RT2561/RT2661")
2036		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2007 "
2037			"Ralink Technology Corporation. All rights reserved."))
2038		.SetLicense(kRalinkFirmware)
2039		.SetURL("http://www.ralinktech.com/"));
2040#endif
2041
2042	// Gutenprint
2043	_AddPackageCredit(PackageCredit("Gutenprint")
2044		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
2045			"1999-2010 by the authors of Gutenprint. All rights reserved."))
2046		.SetLicense(kGPLv2)
2047		.SetURL("http://gutenprint.sourceforge.net/"));
2048
2049	// libwebp
2050	_AddPackageCredit(PackageCredit("libwebp")
2051		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
2052			"2010-2011 Google Inc. All rights reserved."))
2053		.SetLicense(kBSDThreeClause)
2054		.SetURL("http://www.webmproject.org/code/#libwebp_webp_image_library"));
2055
2056	// libavif
2057	_AddPackageCredit(PackageCredit("libavif")
2058		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
2059			"2019 Joe Drago. All rights reserved."))
2060		.SetLicense(kBSDThreeClause)
2061		.SetURL("https://github.com/AOMediaCodec/libavif"));
2062
2063	// GTF
2064	_AddPackageCredit(PackageCredit("GTF")
2065		.SetCopyright(B_TRANSLATE("2001 by Andy Ritger based on the "
2066			"Generalized Timing Formula"))
2067		.SetLicense(kBSDThreeClause)
2068		.SetURL("http://gtf.sourceforge.net/"));
2069
2070	// libqrencode
2071	_AddPackageCredit(PackageCredit("libqrencode")
2072		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2012 Kentaro Fukuchi"))
2073		.SetLicense(kLGPLv21)
2074		.SetURL("http://fukuchi.org/works/qrencode/"));
2075
2076	// scrypt
2077	_AddPackageCredit(PackageCredit("scrypt")
2078		.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2009 Colin Percival"))
2079		.SetLicense(kBSDTwoClause)
2080		.SetURL("https://tarsnap.com/scrypt.html"));
2081
2082	_AddCopyrightsFromAttribute();
2083	_AddPackageCreditEntries();
2084
2085	return new CropView(creditsScroller, 0, 1, 1, 1);
2086}
2087
2088
2089status_t
2090AboutView::_GetLicensePath(const char* license, BPath& path)
2091{
2092	BPathFinder pathFinder;
2093	BStringList paths;
2094	struct stat st;
2095
2096	status_t error = pathFinder.FindPaths(B_FIND_PATH_DATA_DIRECTORY,
2097		"licenses", paths);
2098
2099	for (int i = 0; i < paths.CountStrings(); ++i) {
2100		if (error == B_OK && path.SetTo(paths.StringAt(i)) == B_OK
2101			&& path.Append(license) == B_OK
2102			&& lstat(path.Path(), &st) == 0) {
2103			return B_OK;
2104		}
2105	}
2106
2107	path.Unset();
2108	return B_ENTRY_NOT_FOUND;
2109}
2110
2111
2112void
2113AboutView::_AddCopyrightsFromAttribute()
2114{
2115#ifdef __HAIKU__
2116	// open the app executable file
2117	char appPath[B_PATH_NAME_LENGTH];
2118	int appFD;
2119	if (BPrivate::get_app_path(appPath) != B_OK
2120		|| (appFD = open(appPath, O_RDONLY)) < 0) {
2121		return;
2122	}
2123
2124	// open the attribute
2125	int attrFD = fs_fopen_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
2126	close(appFD);
2127	if (attrFD < 0)
2128		return;
2129
2130	// attach it to a FILE
2131	FileCloser attrFile(fdopen(attrFD, "r"));
2132	if (!attrFile.IsSet()) {
2133		close(attrFD);
2134		return;
2135	}
2136
2137	// read and parse the copyrights
2138	BMessage package;
2139	BString fieldName;
2140	BString fieldValue;
2141	char lineBuffer[LINE_MAX];
2142	while (char* line
2143		= fgets(lineBuffer, sizeof(lineBuffer), attrFile.Get())) {
2144		// chop off line break
2145		size_t lineLen = strlen(line);
2146		if (lineLen > 0 && line[lineLen - 1] == '\n')
2147			line[--lineLen] = '\0';
2148
2149		// flush previous field, if a new field begins, otherwise append
2150		if (lineLen == 0 || !isspace(line[0])) {
2151			// new field -- flush the previous one
2152			if (fieldName.Length() > 0) {
2153				fieldValue = trim_string(fieldValue.String(),
2154					fieldValue.Length());
2155				package.AddString(fieldName.String(), fieldValue);
2156				fieldName = "";
2157			}
2158		} else if (fieldName.Length() > 0) {
2159			// append to current field
2160			fieldValue += line;
2161			continue;
2162		} else {
2163			// bogus line -- ignore
2164			continue;
2165		}
2166
2167		if (lineLen == 0)
2168			continue;
2169
2170		// parse new field
2171		char* colon = strchr(line, ':');
2172		if (colon == NULL) {
2173			// bogus line -- ignore
2174			continue;
2175		}
2176
2177		fieldName.SetTo(line, colon - line);
2178		fieldName = trim_string(line, colon - line);
2179		if (fieldName.Length() == 0) {
2180			// invalid field name
2181			continue;
2182		}
2183
2184		fieldValue = colon + 1;
2185
2186		if (fieldName == "Package") {
2187			// flush the current package
2188			_AddPackageCredit(PackageCredit(package));
2189			package.MakeEmpty();
2190		}
2191	}
2192
2193	// flush current package
2194	_AddPackageCredit(PackageCredit(package));
2195#endif
2196}
2197
2198
2199void
2200AboutView::_AddPackageCreditEntries()
2201{
2202	// sort the packages case-insensitively
2203	PackageCredit* packages[fPackageCredits.size()];
2204	int32 count = 0;
2205	for (PackageCreditMap::iterator it = fPackageCredits.begin();
2206			it != fPackageCredits.end(); ++it) {
2207		packages[count++] = it->second;
2208	}
2209
2210	if (count > 1) {
2211		std::sort(packages, packages + count,
2212			&PackageCredit::NameLessInsensitive);
2213	}
2214
2215	// add the credits
2216	BString text;
2217	for (int32 i = 0; i < count; i++) {
2218		PackageCredit* package = packages[i];
2219
2220		text.SetTo(package->CopyrightAt(0));
2221		int32 count = package->CountCopyrights();
2222		for (int32 i = 1; i < count; i++)
2223			text << "\n" << package->CopyrightAt(i);
2224
2225		AddCopyrightEntry(package->PackageName(), text.String(),
2226			package->Licenses(), package->Sources(), package->URL());
2227	}
2228}
2229
2230
2231void
2232AboutView::_AddPackageCredit(const PackageCredit& package)
2233{
2234	if (!package.IsValid())
2235		return;
2236
2237	PackageCreditMap::iterator it = fPackageCredits.find(package.PackageName());
2238	if (it != fPackageCredits.end()) {
2239		// If the new package credit isn't "better" than the old one, ignore it.
2240		PackageCredit* oldPackage = it->second;
2241		if (!package.IsBetterThan(*oldPackage))
2242			return;
2243
2244		// replace the old credit
2245		fPackageCredits.erase(it);
2246		delete oldPackage;
2247	}
2248
2249	fPackageCredits[package.PackageName()] = new PackageCredit(package);
2250}
2251
2252
2253//	#pragma mark - static functions
2254
2255
2256static int
2257ignored_pages(system_info* sysInfo)
2258{
2259	return (int)round(sysInfo->ignored_pages * B_PAGE_SIZE / 1048576.0);
2260}
2261
2262
2263static int
2264max_pages(system_info* sysInfo)
2265{
2266	return (int)round(sysInfo->max_pages * B_PAGE_SIZE / 1048576.0);
2267}
2268
2269
2270static int
2271max_and_ignored_pages(system_info* sysInfo)
2272{
2273	return max_pages(sysInfo) + ignored_pages(sysInfo);
2274}
2275
2276
2277static int
2278used_pages(system_info* sysInfo)
2279{
2280	return (int)round(sysInfo->used_pages * B_PAGE_SIZE / 1048576.0);
2281}
2282
2283
2284//	#pragma mark - main
2285
2286
2287int
2288main()
2289{
2290	AboutApp app;
2291	app.Run();
2292
2293	return 0;
2294}
2295