xref: /haiku/src/apps/aboutsystem/AboutSystem.cpp (revision cc6e7cb3477cdb34c23be8ce246203d2b7f002de)
1 /*
2  * Copyright (c) 2005-2008, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		René Gollent
8  */
9 
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <sys/utsname.h>
13 #include <time.h>
14 
15 #include <AppFileInfo.h>
16 #include <Application.h>
17 #include <Bitmap.h>
18 #include <File.h>
19 #include <FindDirectory.h>
20 #include <Font.h>
21 #include <fs_attr.h>
22 #include <MessageRunner.h>
23 #include <Messenger.h>
24 #include <OS.h>
25 #include <Path.h>
26 #include <Query.h>
27 #include <Resources.h>
28 #include <Screen.h>
29 #include <ScrollView.h>
30 #include <String.h>
31 #include <StringView.h>
32 #include <TranslationUtils.h>
33 #include <TranslatorFormats.h>
34 #include <View.h>
35 #include <Volume.h>
36 #include <VolumeRoster.h>
37 #include <Window.h>
38 
39 #include <AppMisc.h>
40 #include <AutoDeleter.h>
41 #include <cpu_type.h>
42 
43 #include "HyperTextActions.h"
44 #include "HyperTextView.h"
45 #include "Utilities.h"
46 
47 
48 #define SCROLL_CREDITS_VIEW 'mviv'
49 #define READ_APP_QUERY_ENT 'raqe'
50 
51 
52 static const char *UptimeToString(char string[], size_t size);
53 static const char *MemUsageToString(char string[], size_t size,
54 	system_info *info);
55 
56 static const rgb_color kDarkGrey = { 100, 100, 100, 255 };
57 static const rgb_color kHaikuGreen = { 42, 131, 36, 255 };
58 static const rgb_color kHaikuOrange = { 255, 69, 0, 255 };
59 static const rgb_color kHaikuYellow = { 255, 176, 0, 255 };
60 static const rgb_color kLinkBlue = { 80, 80, 200, 255 };
61 
62 
63 class AboutApp : public BApplication {
64 	public:
65 		AboutApp(void);
66 };
67 
68 class AboutWindow : public BWindow {
69 	public:
70 				AboutWindow(void);
71 		bool	QuitRequested(void);
72 };
73 
74 class AboutView : public BView {
75 	public:
76 				AboutView(const BRect &r);
77 				~AboutView(void);
78 
79 		virtual void AttachedToWindow();
80 		virtual void Pulse();
81 
82 		virtual void FrameResized(float width, float height);
83 		virtual void Draw(BRect update);
84 		virtual void MessageReceived(BMessage *msg);
85 		virtual void MouseDown(BPoint pt);
86 
87 		void	AddCopyrightEntry(const char *name, const char *text,
88 					const Licenses& licenses, const char *url);
89 		void	AddCopyrightEntry(const char *name, const char *text,
90 					const char *url = NULL);
91 		void	AddCopyrightEntry(const BMessage& packageDescription);
92 		void	PickRandomHaiku();
93 
94 	private:
95 		void	_AddCopyrightsFromAttribute();
96 
97 		BStringView		*fMemView;
98 		BStringView		*fUptimeView;
99 		BView			*fInfoView;
100 		HyperTextView	*fCreditsView;
101 
102 		BBitmap			*fLogo;
103 
104 		BPoint			fDrawPoint;
105 
106 		bigtime_t		fLastActionTime;
107 		BMessageRunner	*fScrollRunner;
108 		BQuery			fAppsQuery;
109 };
110 
111 
112 //	#pragma mark -
113 
114 
115 AboutApp::AboutApp(void)
116 	: BApplication("application/x-vnd.Haiku-About")
117 {
118 	AboutWindow *window = new AboutWindow();
119 	window->Show();
120 }
121 
122 
123 //	#pragma mark -
124 
125 
126 AboutWindow::AboutWindow()
127 	: BWindow(BRect(0, 0, 500, 300), "About This System", B_TITLED_WINDOW,
128 			B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
129 {
130 	AboutView *view = new AboutView(Bounds());
131 	AddChild(view);
132 
133 	// start reading from the app query
134 	BMessage msg(READ_APP_QUERY_ENT);
135 	BMessenger msgr(view);
136 	msgr.SendMessage(&msg);
137 
138 	MoveTo((BScreen().Frame().Width() - Bounds().Width()) / 2,
139 		(BScreen().Frame().Height() - Bounds().Height()) / 2 );
140 }
141 
142 
143 bool
144 AboutWindow::QuitRequested()
145 {
146 	be_app->PostMessage(B_QUIT_REQUESTED);
147 	return true;
148 }
149 
150 
151 AboutView::AboutView(const BRect &rect)
152 	: BView(rect, "aboutview", B_FOLLOW_ALL, B_WILL_DRAW | B_PULSE_NEEDED),
153 	fLastActionTime(system_time()),
154 	fScrollRunner(NULL)
155 {
156 	fLogo = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "haikulogo.png");
157 	if (fLogo) {
158 		fDrawPoint.x = (225-fLogo->Bounds().Width()) / 2;
159 		fDrawPoint.y = 0;
160 	}
161 
162 	// Begin Construction of System Information controls
163 
164 	font_height height;
165 	float labelHeight, textHeight;
166 
167 	system_info systemInfo;
168 	get_system_info(&systemInfo);
169 
170 	be_plain_font->GetHeight(&height);
171 	textHeight = height.ascent + height.descent + height.leading;
172 
173 	be_bold_font->GetHeight(&height);
174 	labelHeight = height.ascent + height.descent + height.leading;
175 
176 	BRect r(0, 0, 225, Bounds().bottom);
177 	if (fLogo)
178 		r.OffsetBy(0, fLogo->Bounds().Height());
179 
180 	fInfoView = new BView(r, "infoview", B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
181 		B_WILL_DRAW);
182 	fInfoView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
183 	fInfoView->SetLowColor(fInfoView->ViewColor());
184 	fInfoView->SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
185 	AddChild(fInfoView);
186 
187 	// Add all the various labels for system infomation
188 
189 	BStringView *stringView;
190 
191 	// OS Version
192 	r.Set(5, 5, 224, labelHeight + 5);
193 	stringView = new BStringView(r, "oslabel", "Version:");
194 	stringView->SetFont(be_bold_font);
195 	fInfoView->AddChild(stringView);
196 	stringView->ResizeToPreferred();
197 
198 	// we update "labelHeight" to the actual height of the string view
199 	labelHeight = stringView->Bounds().Height();
200 
201 	r.OffsetBy(0, labelHeight);
202 	r.bottom = r.top + textHeight;
203 
204 	char string[256];
205 	strcpy(string, "Unknown");
206 
207 	// the version is stored in the BEOS:APP_VERSION attribute of libbe.so
208 	BPath path;
209 	if (find_directory(B_BEOS_LIB_DIRECTORY, &path) == B_OK) {
210 		path.Append("libbe.so");
211 
212 		BAppFileInfo appFileInfo;
213 		version_info versionInfo;
214 		BFile file;
215 		if (file.SetTo(path.Path(), B_READ_ONLY) == B_OK
216 			&& appFileInfo.SetTo(&file) == B_OK
217 			&& appFileInfo.GetVersionInfo(&versionInfo,
218 				B_APP_VERSION_KIND) == B_OK
219 			&& versionInfo.short_info[0] != '\0')
220 			strcpy(string, versionInfo.short_info);
221 	}
222 
223 	// Add revision from uname() info
224 	utsname unameInfo;
225 	if (uname(&unameInfo) == 0) {
226 		long revision;
227 		if (sscanf(unameInfo.version, "r%ld", &revision) == 1) {
228 			char version[16];
229 			snprintf(version, sizeof(version), "%ld", revision);
230 			strlcat(string, " (Revision ", sizeof(string));
231 			strlcat(string, version, sizeof(string));
232 			strlcat(string, ")", sizeof(string));
233 		}
234 	}
235 
236 	stringView = new BStringView(r, "ostext", string);
237 	fInfoView->AddChild(stringView);
238 	stringView->ResizeToPreferred();
239 
240 	// CPU count, type and clock speed
241 	r.OffsetBy(0, textHeight * 1.5);
242 	r.bottom = r.top + labelHeight;
243 
244 	if (systemInfo.cpu_count > 1)
245 		sprintf(string, "%ld Processors:", systemInfo.cpu_count);
246 	else
247 		strcpy(string, "Processor:");
248 
249 	stringView = new BStringView(r, "cpulabel", string);
250 	stringView->SetFont(be_bold_font);
251 	fInfoView->AddChild(stringView);
252 	stringView->ResizeToPreferred();
253 
254 	BString cpuType;
255 	cpuType << get_cpu_vendor_string(systemInfo.cpu_type)
256 		<< " " << get_cpu_model_string(&systemInfo);
257 
258 	r.OffsetBy(0, labelHeight);
259 	r.bottom = r.top + textHeight;
260 	stringView = new BStringView(r, "cputext", cpuType.String());
261 	fInfoView->AddChild(stringView);
262 	stringView->ResizeToPreferred();
263 
264 	r.OffsetBy(0, textHeight);
265 	r.bottom = r.top + textHeight;
266 
267 	int32 clockSpeed = get_rounded_cpu_speed();
268 	if (clockSpeed < 1000)
269 		sprintf(string,"%ld MHz", clockSpeed);
270 	else
271 		sprintf(string,"%.2f GHz", clockSpeed / 1000.0f);
272 
273 	stringView = new BStringView(r, "mhztext", string);
274 	fInfoView->AddChild(stringView);
275 	stringView->ResizeToPreferred();
276 
277 	// RAM
278 	r.OffsetBy(0, textHeight * 1.5);
279 	r.bottom = r.top + labelHeight;
280 	stringView = new BStringView(r, "ramlabel", "Memory:");
281 	stringView->SetFont(be_bold_font);
282 	fInfoView->AddChild(stringView);
283 	stringView->ResizeToPreferred();
284 
285 	r.OffsetBy(0, labelHeight);
286 	r.bottom = r.top + textHeight;
287 
288 	fMemView = new BStringView(r, "ramtext", "");
289 	fInfoView->AddChild(fMemView);
290 	fMemView->SetText(MemUsageToString(string, sizeof(string), &systemInfo));
291 
292 	// Kernel build time/date
293 	r.OffsetBy(0, textHeight * 1.5);
294 	r.bottom = r.top + labelHeight;
295 	stringView = new BStringView(r, "kernellabel", "Kernel:");
296 	stringView->SetFont(be_bold_font);
297 	fInfoView->AddChild(stringView);
298 	stringView->ResizeToPreferred();
299 
300 	r.OffsetBy(0, labelHeight);
301 	r.bottom = r.top + textHeight;
302 
303 	snprintf(string, sizeof(string), "%s %s",
304 		systemInfo.kernel_build_date, systemInfo.kernel_build_time);
305 
306 	stringView = new BStringView(r, "kerneltext", string);
307 	fInfoView->AddChild(stringView);
308 	stringView->ResizeToPreferred();
309 
310 	// Uptime
311 	r.OffsetBy(0, textHeight * 1.5);
312 	r.bottom = r.top + labelHeight;
313 	stringView = new BStringView(r, "uptimelabel", "Time Running:");
314 	stringView->SetFont(be_bold_font);
315 	fInfoView->AddChild(stringView);
316 	stringView->ResizeToPreferred();
317 
318 	r.OffsetBy(0, labelHeight);
319 	r.bottom = r.top + textHeight;
320 
321 	fUptimeView = new BStringView(r, "uptimetext", "");
322 	fInfoView->AddChild(fUptimeView);
323 	// string width changes, so we don't do ResizeToPreferred()
324 
325 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
326 
327 	// Begin construction of the credits view
328 	r = Bounds();
329 	r.left += fInfoView->Bounds().right + 1;
330 	r.right -= B_V_SCROLL_BAR_WIDTH;
331 
332 	fCreditsView = new HyperTextView(r, "credits",
333 		r.OffsetToCopy(0, 0).InsetByCopy(5, 5), B_FOLLOW_ALL);
334 	fCreditsView->SetFlags(fCreditsView->Flags() | B_FRAME_EVENTS );
335 	fCreditsView->SetStylable(true);
336 	fCreditsView->MakeEditable(false);
337 	fCreditsView->MakeSelectable(false);
338 	fCreditsView->SetWordWrap(true);
339 
340 	BScrollView *creditsScroller = new BScrollView("creditsScroller",
341 		fCreditsView, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS, false, true,
342 		B_PLAIN_BORDER);
343 	AddChild(creditsScroller);
344 
345 	BFont font(be_bold_font);
346 	font.SetSize(font.Size() + 4);
347 
348 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
349 	fCreditsView->Insert("Haiku\n");
350 
351 	font.SetSize(be_bold_font->Size());
352 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
353 
354 	time_t time = ::time(NULL);
355 	struct tm* tm = localtime(&time);
356 	int32 year = tm->tm_year + 1900;
357 	if (year < 2007)
358 		year = 2007;
359 	snprintf(string, sizeof(string),
360 		"Copyright " B_UTF8_COPYRIGHT "2001-%ld Haiku, Inc.\n", year);
361 
362 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
363 	fCreditsView->Insert(string);
364 
365 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
366 	fCreditsView->InsertHyperText("http://haiku-os.org",
367 		new URLAction("http://haiku-os.org"));
368 	fCreditsView->Insert("\n\n");
369 
370 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
371 	fCreditsView->Insert("Team Leads:\n");
372 
373 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
374 	fCreditsView->Insert(
375 		"Axel Dörfler\n"
376 		"Phil Greenway\n"
377 		"Philippe Houdoin\n"
378 		"Marcus Overhagen\n"
379 		"Ingo Weinhold\n"
380 		"Jonathan Yoder\n"
381 		"\n");
382 
383 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
384 	fCreditsView->Insert("Developers:\n");
385 
386 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
387 	fCreditsView->Insert(
388 		"Ithamar R. Adema\n"
389 		"Bruno G. Albuquerque\n"
390 		"Stephan Aßmus\n"
391 		"Andrew Bachmann\n"
392 		"Salvatore Benedetto\n"
393 		"Stefano Ceccherini\n"
394 		"Rudolf Cornelissen\n"
395 		"Alexandre Deckner\n"
396 		"Oliver Ruiz Dorantes\n"
397 		"Jérôme Duval\n"
398 		"Andre Alves Garzia\n"
399 		"René Gollent\n"
400 		"Karsten Heimrich\n"
401 		"Euan Kirkhope\n"
402 		"Waldemar Kornewald\n"
403 		"Ryan Leavengood\n"
404 		"Michael Lotz\n"
405 		"David McPaul\n"
406 		"Michael Pfeiffer\n"
407 		"Niels Sascha Reedijk\n"
408 		"Jonas Sundström\n"
409 		"François Revol\n"
410 		"Hugo Santos\n"
411 		"Gerasim Troeglazov\n"
412 		"Bryan Varner\n"
413 		"Siarzhuk Zharski\n"
414 		"\n");
415 
416 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
417 	fCreditsView->Insert("Contributors:\n");
418 
419 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
420 	fCreditsView->Insert(
421 		"Andrea Anzani\n"
422 		"Andre Braga\n"
423 		"Bruce Cameron\n"
424 		"Greg Crain\n"
425 		"Tyler Dauwalder\n"
426 		"David Dengg\n"
427 		"John Drinkwater\n"
428 		"Cian Duffy\n"
429 		"Marc Flerackers\n"
430 		"Daniel Furrer\n"
431 		"Matthijs Hollemans\n"
432 		"Morgan Howe\n"
433 		"Erik Jaesler\n"
434 		"Carwyn Jones\n"
435 		"Maurice Kalinowski\n"
436 		"Vasilis Kaoutsis\n"
437 		"James Kim\n"
438 		"Jan Klötzke\n"
439 		"Marcin Konicki\n"
440 		"Kurtis Kopf\n"
441 		"Waldemar Kornewald\n"
442 		"Tomáš Kučera\n"
443 		"Luboš Kulič\n"
444 		"Thomas Kurschel\n"
445 		"Elad Lahav\n"
446 		"Anthony Lee\n"
447 		"Santiago Lema\n"
448 		"Raynald Lesieur\n"
449 		"Oscar Lesta\n"
450 		"Jerome Leveque\n"
451 		"Christof Lutteroth\n"
452 		"Graham MacDonald\n"
453 		"Jan Matějek\n"
454 		"Brian Matzon\n"
455 		"Christopher ML Zumwalt May\n"
456 		"Andrew McCall\n"
457 		"Michele (zuMi)\n"
458 		"Marius Middelthon\n"
459 		"Misza\n"
460 		"Fredrik Modéen\n"
461 		"MrSiggler\n"
462 		"Alan Murta\n"
463 		"Frans Van Nispen\n"
464 		"Adi Oanca\n"
465 		"Pahtz\n"
466 		"Michael Paine\n"
467 		"Michael Phipps\n"
468 		"Jeremy Rand\n"
469 		"Hartmut Reh\n"
470 		"David Reid\n"
471 		"Daniel Reinhold\n"
472 		"Samuel Rodriguez Perez\n"
473 		"Thomas Roell\n"
474 		"Rafael Romo\n"
475 		"Philippe Saint-Pierre\n"
476 		"Reznikov Sergei\n"
477 		"Zousar Shaker\n"
478 		"Alexander G. M. Smith\n"
479 		"Daniel Switkin\n"
480 		"Atsushi Takamatsu\n"
481 		"Oliver Tappe\n"
482 		"James Urquhart\n"
483 		"Jason Vandermark\n"
484 		"Sandor Vroemisse\n"
485 		"Denis Washington\n"
486 		"Nathan Whitehorn\n"
487 		"Michael Wilber\n"
488 		"Ulrich Wimboeck\n"
489 		"James Woodcock\n" // getpagesize() patch
490 		"Artur Wyszynski\n"
491 		"Gabe Yoder\n"
492 		"Gerald Zajac\n"
493 		"Łukasz Zemczak\n"
494 		"JiSheng Zhang\n"
495 		"\n" B_UTF8_ELLIPSIS " and probably some more we forgot to mention "
496 		"(sorry!)"
497 		"\n\n");
498 
499 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuOrange);
500 	fCreditsView->Insert("Special Thanks To:\n");
501 
502 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
503 	fCreditsView->Insert("Travis Geiselbrecht (and his NewOS kernel)\n");
504 	fCreditsView->Insert("Michael Phipps (project founder)\n\n");
505 
506 	// copyrights for various projects we use
507 
508 	font.SetSize(be_bold_font->Size() + 4);
509 	font.SetFace(B_BOLD_FACE);
510 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
511 	fCreditsView->Insert("\nCopyrights\n\n");
512 
513 	// GNU copyrights
514 	AddCopyrightEntry("The GNU Project",
515 		"Contains software from the GNU Project, "
516 		"released under the GPL and LGPL licences:\n"
517 		"GNU C Library, "
518 		"GNU coretools, diffutils, findutils, "
519 		"gawk, bison, m4, make, "
520 		"gdb, wget, ncurses, termcap, "
521 		"Bourne Again Shell.\n"
522 		"Copyright " B_UTF8_COPYRIGHT " The Free Software Foundation.",
523 		Licenses("GNU LGPL v2.1", "GNU GPL v2", "GNU GPL v3", NULL),
524 		"http://www.gnu.org");
525 
526 	// FreeBSD copyrights
527 	AddCopyrightEntry("The FreeBSD Project",
528 		"Contains software from the FreeBSD Project, "
529 		"released under the BSD licence:\n"
530 		"ping, telnet, telnetd, traceroute\n"
531 		"Copyright " B_UTF8_COPYRIGHT " 1994-2008 The FreeBSD Project.  "
532 		"All rights reserved.",
533 		"http://www.freebsd.org");
534 
535 	// NetBSD copyrights
536 	AddCopyrightEntry("The NetBSD Project",
537 		"Contains software developed by the NetBSD, "
538 		"Foundation, Inc. and its contributors:\n"
539 		"ftp\n"
540 		"Copyright " B_UTF8_COPYRIGHT " 1996-2008 The NetBSD Foundation, Inc.  "
541 		"All rights reserved.",
542 		"http://www.netbsd.org");
543 
544 	// FFMpeg copyrights
545 	AddCopyrightEntry("FFMpeg libavcodec",
546 		"Copyright " B_UTF8_COPYRIGHT " 2000-2007 Fabrice Bellard, et al.",
547 		"http://www.ffmpeg.org");
548 
549 	// AGG copyrights
550 	AddCopyrightEntry("AntiGrain Geometry",
551 		"Copyright " B_UTF8_COPYRIGHT " 2002-2006 Maxim Shemanarev (McSeem).",
552 		"http://www.antigrain.com");
553 
554 	// PDFLib copyrights
555 	AddCopyrightEntry("PDFLib",
556 		"Copyright " B_UTF8_COPYRIGHT " 1997-2006 PDFlib GmbH and Thomas Merz. "
557 		"All rights reserved.\n"
558 		"PDFlib and PDFlib logo are registered trademarks of PDFlib GmbH.",
559 		"http://www.pdflib.com");
560 
561 	// FreeType copyrights
562 	AddCopyrightEntry("FreeType2",
563 		"Portions of this software are copyright " B_UTF8_COPYRIGHT " 1996-2006 "
564 		"The FreeType Project.  All rights reserved.",
565 		"http://www.freetype.org");
566 
567 	// Mesa3D (http://www.mesa3d.org) copyrights
568 	AddCopyrightEntry("Mesa",
569 		"Copyright " B_UTF8_COPYRIGHT " 1999-2006 Brian Paul. "
570 		"Mesa3D project.  All rights reserved.",
571 		"http://www.mesa3d.org");
572 
573 	// SGI's GLU implementation copyrights
574 	AddCopyrightEntry("GLU",
575 		"Copyright " B_UTF8_COPYRIGHT " 1991-2000 Silicon Graphics, Inc. "
576 		"SGI's Software FreeB license.  All rights reserved.");
577 
578 	// GLUT implementation copyrights
579 	AddCopyrightEntry("GLUT",
580 		"Copyright " B_UTF8_COPYRIGHT " 1994-1997 Mark Kilgard. "
581 		"All rights reserved.\n"
582 		"Copyright " B_UTF8_COPYRIGHT " 1997 Be Inc.\n"
583 		"Copyright " B_UTF8_COPYRIGHT " 1999 Jake Hamby.");
584 
585 	// OpenGroup & DEC (BRegion backend) copyright
586 	AddCopyrightEntry("BRegion backend (XFree86)",
587 		"Copyright " B_UTF8_COPYRIGHT " 1987, 1988, 1998  The Open Group.\n"
588 		"Copyright " B_UTF8_COPYRIGHT " 1987, 1988 Digital Equipment "
589 		"Corporation, Maynard, Massachusetts.\n"
590 		"All rights reserved.");
591 
592 	// Konatu font
593 	AddCopyrightEntry("Konatu font",
594 		"Copyright " B_UTF8_COPYRIGHT " 2002- MASUDA mitiya.\n"
595 		"MIT license. All rights reserved.");
596 
597 	// expat copyrights
598 	AddCopyrightEntry("expat",
599 		"Copyright " B_UTF8_COPYRIGHT " 1998, 1999, 2000 Thai Open Source "
600 		"Software Center Ltd and Clark Cooper.\n"
601 		"Copyright " B_UTF8_COPYRIGHT " 2001, 2002, 2003 Expat maintainers.");
602 
603 	// zlib copyrights
604 	AddCopyrightEntry("zlib",
605 		"Copyright " B_UTF8_COPYRIGHT " 1995-2004 Jean-loup Gailly and Mark "
606 		"Adler.");
607 
608 	// zip copyrights
609 	AddCopyrightEntry("Info-ZIP",
610 		"Copyright " B_UTF8_COPYRIGHT " 1990-2002 Info-ZIP. All rights reserved.");
611 
612 	// bzip2 copyrights
613 	AddCopyrightEntry("bzip2",
614 		"Copyright " B_UTF8_COPYRIGHT " 1996-2005 Julian R Seward. All rights "
615 		"reserved.");
616 
617 	// VIM copyrights
618 	AddCopyrightEntry("Vi IMproved",
619 		"Copyright " B_UTF8_COPYRIGHT " Bram Moolenaar et al.");
620 
621 	// lp_solve copyrights
622 	AddCopyrightEntry("lp_solve",
623 		"Copyright " B_UTF8_COPYRIGHT
624 			" Michel Berkelaar, Kjell Eikland, Peter Notebaert",
625 		"http://lpsolve.sourceforge.net/");
626 			// license: LGPL
627 
628 	// OpenEXR copyrights
629 	AddCopyrightEntry("OpenEXR",
630 		"Copyright " B_UTF8_COPYRIGHT " 2002-2005 Industrial Light & Magic, "
631 		"a division of Lucas Digital Ltd. LLC.");
632 
633 	// Bullet copyrights
634 	AddCopyrightEntry("Bullet",
635 		"Copyright " B_UTF8_COPYRIGHT " 2003-2008 Erwin Coumans",
636 		"http://www.bulletphysics.com");
637 
638 	// atftp copyrights
639 	AddCopyrightEntry("atftp",
640 		"Copyright " B_UTF8_COPYRIGHT " 2000 Jean-Pierre Lefebvre and Remi "
641 		"Lefebvre");
642 
643 	// Netcat copyrights
644 	AddCopyrightEntry("Netcat",
645 		"Copyright " B_UTF8_COPYRIGHT " 1996 Hobbit");
646 
647 	// acpica copyrights
648 	AddCopyrightEntry("acpica",
649 		"Copyright " B_UTF8_COPYRIGHT " 1999 - 2006 Intel Corp.");
650 
651 	// unrar copyrights
652 	AddCopyrightEntry("unrar",
653 		"Copyright " B_UTF8_COPYRIGHT " Alexander L. Roshal.");
654 
655 	// libpng copyrights
656 	AddCopyrightEntry("libpng",
657 		"Copyright " B_UTF8_COPYRIGHT " 2004, 2006-2008 Glenn "
658 		"Randers-Pehrson.");
659 
660 	// libprint copyrights
661 	AddCopyrightEntry("libprint",
662 		"Copyright " B_UTF8_COPYRIGHT " 1999-2000 Y.Takagi. All Rights "
663 		"Reserved.");
664 
665 	// cortex copyrights
666 	AddCopyrightEntry("Cortex",
667 		"Copyright " B_UTF8_COPYRIGHT " 1999-2000 Eric Moon.");
668 
669 	// FluidSynth copyrights
670 	AddCopyrightEntry("FluidSynth",
671 		"Copyright " B_UTF8_COPYRIGHT " 2003 Peter Hanappe and others.");
672 
673 	// CannaIM copyrights
674 	AddCopyrightEntry("CannaIM",
675 		"Copyright " B_UTF8_COPYRIGHT " 1999 Masao Kawamura.");
676 
677 	// libxml2, libxslt, libexslt copyrights
678 	AddCopyrightEntry("libxml2, libxslt",
679 		"Copyright " B_UTF8_COPYRIGHT " 1998-2003 Daniel Veillard.  All Rights "
680 		"Reserved.");
681 
682 	AddCopyrightEntry("libexslt",
683 		"Copyright " B_UTF8_COPYRIGHT " 2001-2002 Thomas Broyer, Charlie "
684 		"Bozeman and Daniel Veillard.  All Rights Reserved.");
685 
686 	// Xiph.org Foundation copyrights
687 	AddCopyrightEntry("Xiph.org Foundation",
688 		"libvorbis, libogg, libtheora, libspeex"
689 		"Copyright " B_UTF8_COPYRIGHT " 1994-2008 Xiph.Org.  All rights "
690 		"reserved.", "http://www.xiph.org");
691 
692 	// The Tcpdump Group
693 	AddCopyrightEntry("The Tcpdump Group",
694 		"tcpdump, libpcap",
695 		"http://www.tcpdump.org");
696 
697 	_AddCopyrightsFromAttribute();
698 
699 	// Build a list of installed applications and show their
700 	// long version info. Well-behaved apps usually give
701 	// copyright info there.
702 
703 	font.SetSize(be_bold_font->Size() + 4);
704 	font.SetFace(B_BOLD_FACE);
705 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuGreen);
706 	fCreditsView->Insert("\nInstalled applications\n\n");
707 
708 	BVolume bootVolume;
709 	BVolumeRoster().GetBootVolume(&bootVolume);
710 	fAppsQuery.SetVolume(&bootVolume);
711 	if (fAppsQuery.SetPredicate(
712 			"((BEOS:APP_SIG==\"**\")&&(name!=\"*.so\")&&(name!=\"*.rsrc\")&&"
713 			"(BEOS:TYPE==\"application/x-vnd.Be-elfexecutable\"))") >= B_OK) {
714 		fAppsQuery.Fetch();
715 	}
716 }
717 
718 
719 AboutView::~AboutView(void)
720 {
721 	delete fScrollRunner;
722 }
723 
724 
725 void
726 AboutView::AttachedToWindow(void)
727 {
728 	BView::AttachedToWindow();
729 	Window()->SetPulseRate(500000);
730 	SetEventMask(B_POINTER_EVENTS);
731 }
732 
733 
734 void
735 AboutView::MouseDown(BPoint pt)
736 {
737 	BRect r(92, 26, 105, 31);
738 	if (r.Contains(pt)) {
739 		printf("Easter Egg\n");
740 		PickRandomHaiku();
741 	}
742 
743 	if (Bounds().Contains(pt)) {
744 		fLastActionTime = system_time();
745 		delete fScrollRunner;
746 		fScrollRunner = NULL;
747 	}
748 }
749 
750 
751 void
752 AboutView::FrameResized(float width, float height)
753 {
754 	BRect r = fCreditsView->Bounds();
755 	r.OffsetTo(B_ORIGIN);
756 	r.InsetBy(3, 3);
757 	fCreditsView->SetTextRect(r);
758 }
759 
760 
761 void
762 AboutView::Draw(BRect update)
763 {
764 	if (fLogo)
765 		DrawBitmap(fLogo, fDrawPoint);
766 }
767 
768 
769 void
770 AboutView::Pulse(void)
771 {
772 	char string[255];
773 	system_info info;
774 	get_system_info(&info);
775 	fUptimeView->SetText(UptimeToString(string, sizeof(string)));
776 	fMemView->SetText(MemUsageToString(string, sizeof(string), &info));
777 
778 	if (fScrollRunner == NULL && (system_time() > fLastActionTime + 10000000)) {
779 		BMessage message(SCROLL_CREDITS_VIEW);
780 		//fScrollRunner = new BMessageRunner(this, &message, 300000, -1);
781 	}
782 }
783 
784 
785 void
786 AboutView::MessageReceived(BMessage *msg)
787 {
788 	switch (msg->what) {
789 		case SCROLL_CREDITS_VIEW:
790 		{
791 			BScrollBar *scrollBar = fCreditsView->ScrollBar(B_VERTICAL);
792 			if (scrollBar == NULL)
793 				break;
794 			float max, min;
795 			scrollBar->GetRange(&min, &max);
796 			if (scrollBar->Value() < max)
797 				fCreditsView->ScrollBy(0, 5);
798 
799 			break;
800 		}
801 
802 		case READ_APP_QUERY_ENT:
803 		{
804 			BEntry ent;
805 			if (fAppsQuery.GetNextEntry(&ent) < B_OK) {
806 				fAppsQuery.Clear();
807 				fCreditsView->MakeSelectable(true);
808 				break;
809 			}
810 			BFile file;
811 			BPath path;
812 			if (ent.Exists() &&
813 				ent.GetPath(&path) >= B_OK &&
814 				file.SetTo(&ent, B_READ_ONLY) >= B_OK) {
815 				/* filter only apps */
816 				if (strncmp(path.Path(), "/boot/apps", 10) == 0) {
817 					BAppFileInfo appFileInfo(&file);
818 					uint32 flags;
819 					version_info version;
820 					if (appFileInfo.InitCheck() >= B_OK &&
821 						appFileInfo.GetAppFlags(&flags) >= B_OK &&
822 						appFileInfo.GetVersionInfo(&version,
823 							B_APP_VERSION_KIND) >= B_OK) {
824 						//printf("AppFileInfo for %s :\n", path.Path());
825 						//printf("flags: %08x\n", flags);
826 						BString name;
827 						BString info;
828 						name << path.Leaf();
829 						if (strlen(version.short_info) &&
830 							strcmp(version.short_info, path.Leaf()))
831 							name << " (" << version.short_info << ")";
832 						/*
833 						info << "\tVersion: ";
834 						info << version.major << ".";
835 						info << version.middle << ".";
836 						info << version.minor;
837 						char varieties[] = "dabgmf";
838 						if (version.variety > B_FINAL_VERSION)
839 							info << "?";
840 						else
841 							info << varieties[version.variety];
842 						info << version.internal;
843 						info << "\n";
844 						*/
845 						info << version.long_info;
846 						AddCopyrightEntry(name.String(), info.String());
847 
848 					}
849 				}
850 			}
851 			// note for self: read next entry :)
852 			BMessage m(READ_APP_QUERY_ENT);
853 			BMessenger(this).SendMessage(&m);
854 			break;
855 		}
856 
857 		default:
858 			BView::MessageReceived(msg);
859 			break;
860 	}
861 }
862 
863 
864 void
865 AboutView::AddCopyrightEntry(const char *name, const char *text,
866 	const char *url)
867 {
868 	AddCopyrightEntry(name, text, NULL, url);
869 }
870 
871 
872 void
873 AboutView::AddCopyrightEntry(const char *name, const char *text,
874 	const Licenses& licenses, const char *url)
875 {
876 	BFont font(be_bold_font);
877 	//font.SetSize(be_bold_font->Size());
878 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
879 
880 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kHaikuYellow);
881 	fCreditsView->Insert(name);
882 	fCreditsView->Insert("\n");
883 	fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kDarkGrey);
884 	fCreditsView->Insert(text);
885 	fCreditsView->Insert("\n");
886 
887 	if (licenses.CountLicenses() > 0) {
888 		if (licenses.CountLicenses() > 1)
889 			fCreditsView->Insert("Licenses: ");
890 		else
891 			fCreditsView->Insert("License: ");
892 
893 		for (int32 i = 0; i < licenses.CountLicenses(); i++) {
894 			const char* license = licenses.LicenseAt(i);
895 			BString licensePath("/etc/licenses/");
896 			licensePath += license;
897 
898 			if (i > 0)
899 				fCreditsView->Insert(", ");
900 
901 			fCreditsView->InsertHyperText(license,
902 				new OpenFileAction(licensePath));
903 		}
904 
905 		fCreditsView->Insert("\n");
906 	}
907 
908 	if (url) {
909 		fCreditsView->SetFontAndColor(be_plain_font, B_FONT_ALL, &kLinkBlue);
910 		fCreditsView->InsertHyperText(url, new URLAction(url));
911 		fCreditsView->Insert("\n");
912 	}
913 	fCreditsView->Insert("\n");
914 }
915 
916 
917 void
918 AboutView::AddCopyrightEntry(const BMessage& packageDescription)
919 {
920 	const char* package;
921 	const char* copyright;
922 	const char* url;
923 
924 	// package and copyright are mandatory
925 	if (packageDescription.FindString("Package", &package) != B_OK
926 		|| packageDescription.FindString("Copyright", &copyright) != B_OK) {
927 		return;
928 	}
929 
930 	// URL is optional
931 	if (packageDescription.FindString("URL", &url) != B_OK)
932 		url = NULL;
933 
934 	BString copyrightLine("Copyright " B_UTF8_COPYRIGHT " ");
935 	copyrightLine += copyright;
936 
937 	AddCopyrightEntry(package, copyrightLine.String(), packageDescription, url);
938 }
939 
940 
941 void
942 AboutView::PickRandomHaiku()
943 {
944 	BFile fortunes(
945 #ifdef __HAIKU__
946 		"/etc/fortunes/Haiku",
947 #else
948 		"data/etc/fortunes/Haiku",
949 #endif
950 		B_READ_ONLY);
951 	struct stat st;
952 	if (fortunes.InitCheck() < B_OK)
953 		return;
954 	if (fortunes.GetStat(&st) < B_OK)
955 		return;
956 	char *buff = (char *)malloc((size_t)st.st_size + 1);
957 	if (!buff)
958 		return;
959 	buff[(size_t)st.st_size] = '\0';
960 	BList haikuList;
961 	if (fortunes.Read(buff, (size_t)st.st_size) == (ssize_t)st.st_size) {
962 		char *p = buff;
963 		while (p && *p) {
964 			char *e = strchr(p, '%');
965 			BString *s = new BString(p, e ? (e - p) : -1);
966 			haikuList.AddItem(s);
967 			p = e;
968 			if (p && (*p == '%'))
969 				p++;
970 			if (p && (*p == '\n'))
971 				p++;
972 		}
973 	}
974 	free(buff);
975 	if (haikuList.CountItems() < 1)
976 		return;
977 	BString *s = (BString *)haikuList.ItemAt(rand() % haikuList.CountItems());
978 	BFont font(be_bold_font);
979 	font.SetSize(be_bold_font->Size());
980 	font.SetFace(B_BOLD_FACE | B_ITALIC_FACE);
981 	fCreditsView->SelectAll();
982 	fCreditsView->Delete();
983 	fCreditsView->SetFontAndColor(&font, B_FONT_ALL, &kDarkGrey);
984 	fCreditsView->Insert(s->String());
985 	fCreditsView->Insert("\n");
986 	while ((s = (BString *)haikuList.RemoveItem((int32)0))) {
987 		delete s;
988 	}
989 }
990 
991 
992 void
993 AboutView::_AddCopyrightsFromAttribute()
994 {
995 	// open the app executable file
996 	char appPath[B_PATH_NAME_LENGTH];
997 	int appFD;
998 	if (BPrivate::get_app_path(appPath) != B_OK
999 		|| (appFD = open(appPath, O_RDONLY)) < 0) {
1000 		return;
1001 	}
1002 
1003 	// open the attribute
1004 	int attrFD = fs_open_attr(appFD, "COPYRIGHTS", B_STRING_TYPE, O_RDONLY);
1005 	close(appFD);
1006 	if (attrFD < 0)
1007 		return;
1008 
1009 	// attach it to a FILE
1010 	FILE* attrFile = fdopen(attrFD, "r");
1011 	if (attrFile == NULL) {
1012 		close(attrFD);
1013 		return;
1014 	}
1015 	CObjectDeleter<FILE, int> _(attrFile, fclose);
1016 
1017 	// read and parse the copyrights
1018 	BMessage package;
1019 	BString fieldName;
1020 	BString fieldValue;
1021 	char lineBuffer[LINE_MAX];
1022 	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), attrFile)) {
1023 		// chop off line break
1024 		size_t lineLen = strlen(line);
1025 		if (lineLen > 0 && line[lineLen - 1] == '\n')
1026 			line[--lineLen] = '\0';
1027 
1028 		// flush previous field, if a new field begins, otherwise append
1029 		if (lineLen == 0 || !isspace(line[0])) {
1030 			// new field -- flush the previous one
1031 			if (fieldName.Length() > 0) {
1032 				fieldValue = trim_string(fieldValue.String(),
1033 					fieldValue.Length());
1034 				package.AddString(fieldName.String(), fieldValue);
1035 				fieldName = "";
1036 			}
1037 		} else if (fieldName.Length() > 0) {
1038 			// append to current field
1039 			fieldValue += line;
1040 			continue;
1041 		} else {
1042 			// bogus line -- ignore
1043 			continue;
1044 		}
1045 
1046 		if (lineLen == 0)
1047 			continue;
1048 
1049 		// parse new field
1050 		char* colon = strchr(line, ':');
1051 		if (colon == NULL) {
1052 			// bogus line -- ignore
1053 			continue;
1054 		}
1055 
1056 		fieldName.SetTo(line, colon - line);
1057 		fieldName = trim_string(line, colon - line);
1058 		if (fieldName.Length() == 0) {
1059 			// invalid field name
1060 			continue;
1061 		}
1062 
1063 		fieldValue = colon + 1;
1064 
1065 		if (fieldName == "Package") {
1066 			// flush the current package
1067 			AddCopyrightEntry(package);
1068 			package.MakeEmpty();
1069 		}
1070 	}
1071 
1072 	// flush current package
1073 	AddCopyrightEntry(package);
1074 }
1075 
1076 
1077 //	#pragma mark -
1078 
1079 
1080 static const char *
1081 MemUsageToString(char string[], size_t size, system_info *info)
1082 {
1083 	snprintf(string, size, "%d MB total, %d MB used (%d%%)",
1084 			int(info->max_pages / 256.0f + 0.5f),
1085 			int(info->used_pages / 256.0f + 0.5f),
1086 			int(100 * info->used_pages / info->max_pages));
1087 
1088 	return string;
1089 }
1090 
1091 
1092 static const char *
1093 UptimeToString(char string[], size_t size)
1094 {
1095 	int64 days, hours, minutes, seconds, remainder;
1096 	int64 systime = system_time();
1097 
1098 	days = systime / 86400000000LL;
1099 	remainder = systime % 86400000000LL;
1100 
1101 	hours = remainder / 3600000000LL;
1102 	remainder = remainder % 3600000000LL;
1103 
1104 	minutes = remainder / 60000000;
1105 	remainder = remainder % 60000000;
1106 
1107 	seconds = remainder / 1000000;
1108 
1109 	char *str = string;
1110 	if (days) {
1111 		str += snprintf(str, size, "%lld day%s",days, days > 1 ? "s" : "");
1112 	}
1113 	if (hours) {
1114 		str += snprintf(str, size - strlen(string), "%s%lld hour%s",
1115 				str != string ? ", " : "",
1116 				hours, hours > 1 ? "s" : "");
1117 	}
1118 	if (minutes) {
1119 		str += snprintf(str, size - strlen(string), "%s%lld minute%s",
1120 				str != string ? ", " : "",
1121 				minutes, minutes > 1 ? "s" : "");
1122 	}
1123 
1124 	if (seconds || str == string) {
1125 		// Haiku would be well-known to boot very fast.
1126 		// Let's be ready to handle below minute uptime, zero second included ;-)
1127 		str += snprintf(str, size - strlen(string), "%s%lld second%s",
1128 				str != string ? ", " : "",
1129 				seconds, seconds > 1 ? "s" : "");
1130 	}
1131 
1132 	return string;
1133 }
1134 
1135 
1136 int
1137 main()
1138 {
1139 	AboutApp app;
1140 	app.Run();
1141 	return 0;
1142 }
1143 
1144