xref: /haiku/src/apps/pulse/PulseApp.cpp (revision 97dfeb96704e5dbc5bec32ad7b21379d0125e031)
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 
37 PulseApp::PulseApp(int argc, char **argv)
38 	: BApplication(APP_SIGNATURE)
39 {
40 	prefs = new Prefs();
41 
42 	int mini = false, deskbar = false, normal = false;
43 	uint32 framecolor = 0, activecolor = 0, idlecolor = 0;
44 
45 	while (1) {
46 		int option_index = 0;
47 		static struct option long_options[] = {
48 			{"deskbar", 0, &deskbar, true},
49 			{"width", 1, 0, 'w'},
50 			{"framecolor", 1, 0, 0},
51 			{"activecolor", 1, 0, 0},
52 			{"idlecolor", 1, 0, 0},
53 			{"mini", 0, &mini, true},
54 			{"normal", 0, &normal, true},
55 			{"help", 0, 0, 'h'},
56 			{0,0,0,0}
57 		};
58 		int c = getopt_long(argc, argv, "hw:", long_options, &option_index);
59 		if (c == -1)
60 			break;
61 
62 		switch (c) {
63 			case 0:
64 				switch (option_index) {
65 					case 2: /* framecolor */
66 					case 3: /* activecolor */
67 					case 4: /* idlecolor */
68 						uint32 rgb = strtoul(optarg, NULL, 0);
69 						rgb = rgb << 8;
70 						rgb |= 0x000000ff;
71 
72 						switch (option_index) {
73 							case 2:
74 								framecolor = rgb;
75 								break;
76 							case 3:
77 								activecolor = rgb;
78 								break;
79 							case 4:
80 								idlecolor = rgb;
81 								break;
82 						}
83 						break;
84 				}
85 				break;
86 			case 'w':
87 				prefs->deskbar_icon_width = atoi(optarg);
88 				if (prefs->deskbar_icon_width < GetMinimumViewWidth())
89 					prefs->deskbar_icon_width = GetMinimumViewWidth();
90 				else if (prefs->deskbar_icon_width > 50) prefs->deskbar_icon_width = 50;
91 				break;
92 			case 'h':
93 			case '?':
94 				Usage();
95 				break;
96 			default:
97 				printf("?? getopt returned character code 0%o ??\n", c);
98 				break;
99 		}
100 	}
101 
102 	if (deskbar) {
103 		prefs->window_mode = DESKBAR_MODE;
104 		if (activecolor != 0)
105 			prefs->deskbar_active_color = activecolor;
106 		if (idlecolor != 0)
107 			prefs->deskbar_idle_color = idlecolor;
108 		if (framecolor != 0)
109 			prefs->deskbar_frame_color = framecolor;
110 	} else if (mini) {
111 		prefs->window_mode = MINI_WINDOW_MODE;
112 		if (activecolor != 0)
113 			prefs->mini_active_color = activecolor;
114 		if (idlecolor != 0)
115 			prefs->mini_idle_color = idlecolor;
116 		if (framecolor != 0)
117 			prefs->mini_frame_color = framecolor;
118 	} else if (normal)
119 		prefs->window_mode = NORMAL_WINDOW_MODE;
120 
121 	prefs->Save();
122 	BuildPulse();
123 }
124 
125 
126 void
127 PulseApp::BuildPulse()
128 {
129 	// Remove this case for Deskbar add on API
130 
131 	// If loading the replicant fails, launch the app instead
132 	// This allows having the replicant and the app open simultaneously
133 	if (prefs->window_mode == DESKBAR_MODE && LoadInDeskbar()) {
134 		PostMessage(new BMessage(B_QUIT_REQUESTED));
135 		return;
136 	} else if (prefs->window_mode == DESKBAR_MODE)
137 		prefs->window_mode = NORMAL_WINDOW_MODE;
138 
139 	PulseWindow *pulseWindow = NULL;
140 
141 	if (prefs->window_mode == MINI_WINDOW_MODE)
142 		pulseWindow = new PulseWindow(prefs->mini_window_rect);
143 	else
144 		pulseWindow = new PulseWindow(prefs->normal_window_rect);
145 
146 	pulseWindow->MoveOnScreen(B_MOVE_IF_PARTIALLY_OFFSCREEN);
147 	pulseWindow->Show();
148 }
149 
150 
151 PulseApp::~PulseApp()
152 {
153 	// Load the replicant after we save our preferences so they don't
154 	// get overwritten by DeskbarPulseView's instance
155 	prefs->Save();
156 	if (prefs->window_mode == DESKBAR_MODE)
157 		LoadInDeskbar();
158 
159 	delete prefs;
160 }
161 
162 
163 void
164 PulseApp::AboutRequested()
165 {
166 	PulseApp::ShowAbout(true);
167 }
168 
169 
170 void
171 PulseApp::ShowAbout(bool asApplication)
172 {
173 	// static version to be used in replicant mode
174 	BString name;
175 	if (asApplication)
176 		name = B_TRANSLATE_SYSTEM_NAME("Pulse");
177 	else
178 		name = B_TRANSLATE("Pulse");
179 
180 	BString message = B_TRANSLATE(
181 		"%s\n\nBy David Ramsey and Arve Hjønnevåg\n"
182 		"Revised by Daniel Switkin\n");
183 	message.ReplaceFirst("%s", name);
184 	BAlert *alert = new BAlert(B_TRANSLATE("Info"),
185 		message.String(), B_TRANSLATE("OK"));
186 
187 	BTextView* view = alert->TextView();
188 	BFont font;
189 
190 	view->SetStylable(true);
191 	view->GetFont(&font);
192 
193 	font.SetSize(18);
194 	font.SetFace(B_BOLD_FACE);
195 	view->SetFontAndColor(0, name.Length(), &font);
196 	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
197 	// Use the asynchronous version so we don't block the window's thread
198 	alert->Go(NULL);
199 }
200 
201 //	#pragma mark -
202 
203 
204 /** Make sure we don't disable the last CPU - this is needed by
205  *	descendants of PulseView for the popup menu and for CPUButton
206  *	both as a replicant and not.
207  */
208 
209 bool
210 LastEnabledCPU(unsigned int my_cpu)
211 {
212 	system_info sys_info;
213 	get_system_info(&sys_info);
214 	if (sys_info.cpu_count == 1)
215 		return true;
216 
217 	for (unsigned int x = 0; x < sys_info.cpu_count; x++) {
218 		if (x == my_cpu)
219 			continue;
220 		if (_kern_cpu_enabled(x) == 1)
221 			return false;
222 	}
223 	return true;
224 }
225 
226 
227 /**	Ensure that the mini mode and deskbar mode always show an indicator
228  *	for each CPU, at least one pixel wide.
229  */
230 
231 int
232 GetMinimumViewWidth()
233 {
234 	system_info sys_info;
235 	get_system_info(&sys_info);
236 	return (sys_info.cpu_count * 2) + 1;
237 }
238 
239 
240 void
241 Usage()
242 {
243 	printf(B_TRANSLATE("Usage: Pulse [--mini] [-w width] [--width=width]\n"
244 	       "\t[--deskbar] [--normal] [--framecolor 0xrrggbb]\n"
245 	       "\t[--activecolor 0xrrggbb] [--idlecolor 0xrrggbb]\n"));
246 	exit(0);
247 }
248 
249 
250 bool
251 LoadInDeskbar()
252 {
253 	PulseApp *pulseapp = (PulseApp *)be_app;
254 	BDeskbar *deskbar = new BDeskbar();
255 	// Don't allow two copies in the Deskbar at once
256 	if (deskbar->HasItem("DeskbarPulseView")) {
257 		delete deskbar;
258 		return false;
259 	}
260 
261 	// Must be 16 pixels high, the width is retrieved from the Prefs class
262 	int width = pulseapp->prefs->deskbar_icon_width;
263 	int min_width = GetMinimumViewWidth();
264 	if (width < min_width) {
265 		pulseapp->prefs->deskbar_icon_width = min_width;
266 		width = min_width;
267 	}
268 
269 	BRect rect(0, 0, width - 1, 15);
270 	DeskbarPulseView *replicant = new DeskbarPulseView(rect);
271 	status_t err = deskbar->AddItem(replicant);
272 	delete replicant;
273 	delete deskbar;
274 	if (err != B_OK) {
275 		BString message;
276 		snprintf(message.LockBuffer(512), 512,
277 			B_TRANSLATE("Installing in Deskbar failed\n%s"), strerror(err));
278 		message.UnlockBuffer();
279 		BAlert *alert = new BAlert(B_TRANSLATE("Error"),
280 			message.String(), B_TRANSLATE("OK"));
281 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
282 		alert->Go(NULL);
283 		return false;
284 	}
285 
286 	return true;
287 }
288 
289 
290 int
291 main(int argc, char **argv)
292 {
293 	PulseApp *pulseapp = new PulseApp(argc, argv);
294 	pulseapp->Run();
295 	delete pulseapp;
296 	return 0;
297 }
298