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