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