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