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