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