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