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