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