xref: /haiku/src/apps/pulse/PulseApp.cpp (revision e04f6f31b08f57dfd8a75d3f399666b76f23b22a)
1 /*
2  * Copyright 2002-2005 Haiku
3  * Distributed under the terms of the MIT license.
4  *
5  * Updated by Sikosis (beos@gravity24hr.com)
6  *
7  * Copyright 1999, Be Incorporated. All Rights Reserved.
8  * This file may be used under the terms of the Be Sample Code License.
9  *
10  * Written by:	Daniel Switkin
11  */
12 
13 
14 #include "PulseApp.h"
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <getopt.h>
20 
21 #include <Alert.h>
22 #include <Catalog.h>
23 #include <Deskbar.h>
24 #include <Rect.h>
25 #include <TextView.h>
26 
27 #include <syscalls.h>
28 
29 #include "Common.h"
30 #include "PulseWindow.h"
31 #include "DeskbarPulseView.h"
32 
33 #undef B_TRANSLATION_CONTEXT
34 #define B_TRANSLATION_CONTEXT "PulseApp"
35 
36 
PulseApp(int argc,char ** argv)37 PulseApp::PulseApp(int argc, char **argv)
38 	: BApplication(APP_SIGNATURE),
39 	fPrefs(new Prefs()),
40 	fRunFromReplicant(false),
41 	fIsRunning(false),
42 	fPrefsWindow(NULL)
43 {
44 	int mini = false, deskbar = false, normal = false;
45 	uint32 framecolor = 0, activecolor = 0, idlecolor = 0;
46 
47 	while (1) {
48 		int option_index = 0;
49 		static struct option long_options[] = {
50 			{"deskbar", 0, &deskbar, true},
51 			{"width", 1, 0, 'w'},
52 			{"framecolor", 1, 0, 0},
53 			{"activecolor", 1, 0, 0},
54 			{"idlecolor", 1, 0, 0},
55 			{"mini", 0, &mini, true},
56 			{"normal", 0, &normal, true},
57 			{"help", 0, 0, 'h'},
58 			{0,0,0,0}
59 		};
60 		int c = getopt_long(argc, argv, "hw:", long_options, &option_index);
61 		if (c == -1)
62 			break;
63 
64 		switch (c) {
65 			case 0:
66 				switch (option_index) {
67 					case 2: /* framecolor */
68 					case 3: /* activecolor */
69 					case 4: /* idlecolor */
70 						uint32 rgb = strtoul(optarg, NULL, 0);
71 						rgb = rgb << 8;
72 						rgb |= 0x000000ff;
73 
74 						switch (option_index) {
75 							case 2:
76 								framecolor = rgb;
77 								break;
78 							case 3:
79 								activecolor = rgb;
80 								break;
81 							case 4:
82 								idlecolor = rgb;
83 								break;
84 						}
85 						break;
86 				}
87 				break;
88 			case 'w':
89 				fPrefs->deskbar_icon_width = atoi(optarg);
90 				if (fPrefs->deskbar_icon_width < GetMinimumViewWidth())
91 					fPrefs->deskbar_icon_width = GetMinimumViewWidth();
92 				else if (fPrefs->deskbar_icon_width > 50) fPrefs->deskbar_icon_width = 50;
93 				break;
94 			case 'h':
95 			case '?':
96 				Usage();
97 				break;
98 			default:
99 				printf("?? getopt returned character code 0%o ??\n", c);
100 				break;
101 		}
102 	}
103 
104 	if (deskbar) {
105 		fPrefs->window_mode = DESKBAR_MODE;
106 		if (activecolor != 0)
107 			fPrefs->deskbar_active_color = activecolor;
108 		if (idlecolor != 0)
109 			fPrefs->deskbar_idle_color = idlecolor;
110 		if (framecolor != 0)
111 			fPrefs->deskbar_frame_color = framecolor;
112 	} else if (mini) {
113 		fPrefs->window_mode = MINI_WINDOW_MODE;
114 		if (activecolor != 0)
115 			fPrefs->mini_active_color = activecolor;
116 		if (idlecolor != 0)
117 			fPrefs->mini_idle_color = idlecolor;
118 		if (framecolor != 0)
119 			fPrefs->mini_frame_color = framecolor;
120 	} else if (normal)
121 		fPrefs->window_mode = NORMAL_WINDOW_MODE;
122 
123 	fPrefs->Save();
124 }
125 
126 
127 void
ReadyToRun()128 PulseApp::ReadyToRun()
129 {
130 	if (!fRunFromReplicant)
131 		BuildPulse();
132 
133 	fIsRunning = true;
134 }
135 
136 
137 void
BuildPulse()138 PulseApp::BuildPulse()
139 {
140 	PulseWindow *pulseWindow = NULL;
141 
142 	if (fPrefs->window_mode == MINI_WINDOW_MODE)
143 		pulseWindow = new PulseWindow(fPrefs->mini_window_rect);
144 	else
145 		pulseWindow = new PulseWindow(fPrefs->normal_window_rect);
146 
147 	pulseWindow->MoveOnScreen(B_MOVE_IF_PARTIALLY_OFFSCREEN);
148 	pulseWindow->Show();
149 }
150 
151 
~PulseApp()152 PulseApp::~PulseApp()
153 {
154 	fPrefs->Save();
155 
156 	delete fPrefs;
157 }
158 
159 
160 void
MessageReceived(BMessage * message)161 PulseApp::MessageReceived(BMessage* message)
162 {
163 	switch (message->what) {
164 		case PV_PREFERENCES:
165 		{
166 			// This message can be posted before ReadyToRun from
167 			// BRoster::Launch, in that case, take note to not show the main
168 			// window but only the preferences
169 			if (!fIsRunning)
170 				fRunFromReplicant = true;
171 			BMessenger from;
172 			message->FindMessenger("settingsListener", &from);
173 
174 
175 			if (fPrefsWindow != NULL) {
176 				fPrefsWindow->Activate(true);
177 				break;
178 			}
179 			// If the window is already open, bring it to the front
180 			if (fPrefsWindow != NULL) {
181 				fPrefsWindow->Activate(true);
182 				break;
183 			}
184 			// Otherwise launch a new preferences window
185 			PulseApp *pulseapp = (PulseApp *)be_app;
186 			fPrefsWindow = new PrefsWindow(pulseapp->fPrefs->prefs_window_rect,
187 				B_TRANSLATE("Pulse settings"), &from,
188 				pulseapp->fPrefs);
189 			if (fRunFromReplicant) {
190 				fPrefsWindow->SetFlags(fPrefsWindow->Flags()
191 					| B_QUIT_ON_WINDOW_CLOSE);
192 			}
193 			fPrefsWindow->Show();
194 
195 			break;
196 		}
197 
198 		case PV_ABOUT:
199 			// This message can be posted before ReadyToRun from
200 			// BRoster::Launch, in that case, take note to not show the main
201 			// window but only the about box
202 			if (!fIsRunning)
203 				fRunFromReplicant = true;
204 			PostMessage(B_ABOUT_REQUESTED);
205 			break;
206 
207 		case PRV_QUIT:
208 			fPrefsWindow = NULL;
209 			fRunFromReplicant = false;
210 			break;
211 
212 		default:
213 			BApplication::MessageReceived(message);
214 			break;
215 	}
216 }
217 
218 
219 void
AboutRequested()220 PulseApp::AboutRequested()
221 {
222 	BString name = B_TRANSLATE("Pulse");
223 
224 	BString message = B_TRANSLATE(
225 		"%s\n\nBy David Ramsey and Arve Hjønnevåg\n"
226 		"Revised by Daniel Switkin\n");
227 	message.ReplaceFirst("%s", name);
228 	BAlert *alert = new BAlert(B_TRANSLATE("Info"),
229 		message.String(), B_TRANSLATE("OK"));
230 
231 	if (fRunFromReplicant)
232 		alert->SetFlags(alert->Flags() | B_QUIT_ON_WINDOW_CLOSE);
233 
234 	BTextView* view = alert->TextView();
235 	BFont font;
236 
237 	view->SetStylable(true);
238 	view->GetFont(&font);
239 
240 	font.SetSize(18);
241 	font.SetFace(B_BOLD_FACE);
242 	view->SetFontAndColor(0, name.Length(), &font);
243 	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
244 	// Use the asynchronous version so we don't block the window's thread
245 	alert->Go(NULL);
246 	fRunFromReplicant = false;
247 }
248 
249 //	#pragma mark -
250 
251 
252 /** Make sure we don't disable the last CPU - this is needed by
253  *	descendants of PulseView for the popup menu and for CPUButton
254  *	both as a replicant and not.
255  */
256 
257 bool
LastEnabledCPU(unsigned int my_cpu)258 LastEnabledCPU(unsigned int my_cpu)
259 {
260 	system_info sys_info;
261 	get_system_info(&sys_info);
262 	if (sys_info.cpu_count == 1)
263 		return true;
264 
265 	for (unsigned int x = 0; x < sys_info.cpu_count; x++) {
266 		if (x == my_cpu)
267 			continue;
268 		if (_kern_cpu_enabled(x) == 1)
269 			return false;
270 	}
271 	return true;
272 }
273 
274 
275 /**	Ensure that the mini mode and deskbar mode always show an indicator
276  *	for each CPU, at least one pixel wide.
277  */
278 
279 int
GetMinimumViewWidth()280 GetMinimumViewWidth()
281 {
282 	system_info sys_info;
283 	get_system_info(&sys_info);
284 	return (sys_info.cpu_count * 2) + 1;
285 }
286 
287 
288 void
Usage()289 Usage()
290 {
291 	puts(B_TRANSLATE("Usage: Pulse [--mini] [-w width] [--width=width]\n"
292 		"\t[--deskbar] [--normal] [--framecolor 0xrrggbb]\n"
293 		"\t[--activecolor 0xrrggbb] [--idlecolor 0xrrggbb]"));
294 	exit(0);
295 }
296 
297 
298 bool
LoadInDeskbar()299 LoadInDeskbar()
300 {
301 	PulseApp *pulseapp = (PulseApp *)be_app;
302 	BDeskbar *deskbar = new BDeskbar();
303 	// Don't allow two copies in the Deskbar at once
304 	if (deskbar->HasItem("DeskbarPulseView")) {
305 		delete deskbar;
306 		return false;
307 	}
308 
309 	// Must be 16 pixels high, the width is retrieved from the Prefs class
310 	int width = pulseapp->fPrefs->deskbar_icon_width;
311 	int min_width = GetMinimumViewWidth();
312 	if (width < min_width) {
313 		pulseapp->fPrefs->deskbar_icon_width = min_width;
314 		width = min_width;
315 	}
316 
317 	float height = deskbar->MaxItemHeight();
318 	BRect rect(0, 0, width - 1, height - 1);
319 	DeskbarPulseView *replicant = new DeskbarPulseView(rect);
320 	status_t err = deskbar->AddItem(replicant);
321 	delete replicant;
322 	delete deskbar;
323 	if (err != B_OK) {
324 		BString message;
325 		snprintf(message.LockBuffer(512), 512,
326 			B_TRANSLATE("Installing in Deskbar failed\n%s"), strerror(err));
327 		message.UnlockBuffer();
328 		BAlert *alert = new BAlert(B_TRANSLATE("Error"),
329 			message.String(), B_TRANSLATE("OK"));
330 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
331 		alert->Go(NULL);
332 		return false;
333 	}
334 
335 	return true;
336 }
337 
338 
339 int
main(int argc,char ** argv)340 main(int argc, char **argv)
341 {
342 	PulseApp *pulseapp = new PulseApp(argc, argv);
343 	pulseapp->Run();
344 	delete pulseapp;
345 	return 0;
346 }
347