xref: /haiku/src/apps/powerstatus/PowerStatusView.cpp (revision 6d2f2ec177bf615a117a7428d71be4330545b320)
1 /*
2  * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Clemens Zeidler, haiku@Clemens-Zeidler.de
8  *		Alexander von Gluck, kallisti5@unixzen.com
9  */
10 
11 
12 #include "PowerStatusView.h"
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 
19 #include <AboutWindow.h>
20 #include <Application.h>
21 #include <Bitmap.h>
22 #include <Catalog.h>
23 #include <ControlLook.h>
24 #include <DataIO.h>
25 #include <Deskbar.h>
26 #include <Dragger.h>
27 #include <Drivers.h>
28 #include <File.h>
29 #include <FindDirectory.h>
30 #include <MenuItem.h>
31 #include <MessageRunner.h>
32 #include <Notification.h>
33 #include <Path.h>
34 #include <PopUpMenu.h>
35 #include <Resources.h>
36 #include <TextView.h>
37 #include <TranslationUtils.h>
38 
39 #include "ACPIDriverInterface.h"
40 #include "APMDriverInterface.h"
41 #include "ExtendedInfoWindow.h"
42 #include "PowerStatus.h"
43 
44 
45 #undef B_TRANSLATION_CONTEXT
46 #define B_TRANSLATION_CONTEXT "PowerStatus"
47 
48 
49 extern "C" _EXPORT BView *instantiate_deskbar_item(void);
50 extern const char* kDeskbarItemName;
51 
52 const uint32 kMsgToggleLabel = 'tglb';
53 const uint32 kMsgToggleTime = 'tgtm';
54 const uint32 kMsgToggleStatusIcon = 'tgsi';
55 const uint32 kMsgToggleExtInfo = 'texi';
56 
57 const uint32 kMinIconWidth = 16;
58 const uint32 kMinIconHeight = 16;
59 
60 const int32 kLowBatteryPercentage = 15;
61 const int32 kNoteBatteryPercentage = 30;
62 
63 
64 PowerStatusView::PowerStatusView(PowerStatusDriverInterface* interface,
65 	BRect frame, int32 resizingMode,  int batteryID, bool inDeskbar)
66 	:
67 	BView(frame, kDeskbarItemName, resizingMode,
68 		B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
69 	fDriverInterface(interface),
70 	fBatteryID(batteryID),
71 	fInDeskbar(inDeskbar)
72 {
73 	_Init();
74 }
75 
76 
77 PowerStatusView::PowerStatusView(BMessage* archive)
78 	: BView(archive)
79 {
80 	_Init();
81 	FromMessage(archive);
82 }
83 
84 
85 PowerStatusView::~PowerStatusView()
86 {
87 }
88 
89 
90 status_t
91 PowerStatusView::Archive(BMessage* archive, bool deep) const
92 {
93 	status_t status = BView::Archive(archive, deep);
94 	if (status == B_OK)
95 		status = ToMessage(archive);
96 
97 	return status;
98 }
99 
100 
101 void
102 PowerStatusView::_Init()
103 {
104 	SetViewColor(B_TRANSPARENT_COLOR);
105 
106 	fShowLabel = true;
107 	fShowTime = false;
108 	fShowStatusIcon = true;
109 
110 	fPercent = 100;
111 	fOnline = true;
112 	fTimeLeft = 0;
113 }
114 
115 
116 void
117 PowerStatusView::AttachedToWindow()
118 {
119 	BView::AttachedToWindow();
120 	if (Parent())
121 		SetLowColor(Parent()->ViewColor());
122 	else
123 		SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
124 
125 	Update();
126 }
127 
128 
129 void
130 PowerStatusView::DetachedFromWindow()
131 {
132 }
133 
134 
135 void
136 PowerStatusView::MessageReceived(BMessage *message)
137 {
138 	switch (message->what) {
139 		case kMsgUpdate:
140 			Update();
141 			break;
142 
143 		default:
144 			BView::MessageReceived(message);
145 	}
146 }
147 
148 
149 void
150 PowerStatusView::_DrawBattery(BRect rect)
151 {
152 	float quarter = floorf((rect.Height() + 1) / 4);
153 	rect.top += quarter;
154 	rect.bottom -= quarter;
155 
156 	rect.InsetBy(2, 0);
157 
158 	float left = rect.left;
159 	rect.left += rect.Width() / 11;
160 
161 	SetHighColor(0, 0, 0);
162 
163 	float gap = 1;
164 	if (rect.Height() > 8) {
165 		gap = ceilf((rect.left - left) / 2);
166 
167 		// left
168 		FillRect(BRect(rect.left, rect.top, rect.left + gap - 1, rect.bottom));
169 		// right
170 		FillRect(BRect(rect.right - gap + 1, rect.top, rect.right,
171 			rect.bottom));
172 		// top
173 		FillRect(BRect(rect.left + gap, rect.top, rect.right - gap,
174 			rect.top + gap - 1));
175 		// bottom
176 		FillRect(BRect(rect.left + gap, rect.bottom + 1 - gap,
177 			rect.right - gap, rect.bottom));
178 	} else
179 		StrokeRect(rect);
180 
181 	FillRect(BRect(left, floorf(rect.top + rect.Height() / 4) + 1,
182 		rect.left - 1, floorf(rect.bottom - rect.Height() / 4)));
183 
184 	int32 percent = fPercent;
185 	if (percent > 100)
186 		percent = 100;
187 	else if (percent < 0 || !fHasBattery)
188 		percent = 0;
189 
190 	if (percent > 0) {
191 		rect.InsetBy(gap, gap);
192 		rgb_color base = {84, 84, 84, 255};
193 		if (be_control_look != NULL) {
194 			BRect empty = rect;
195 			if (fHasBattery && percent > 0)
196 				empty.left += empty.Width() * percent / 100.0;
197 
198 			be_control_look->DrawButtonBackground(this, empty, empty, base,
199 				fHasBattery
200 					? BControlLook::B_ACTIVATED : BControlLook::B_DISABLED,
201 				fHasBattery && percent > 0
202 					? (BControlLook::B_ALL_BORDERS
203 						& ~BControlLook::B_LEFT_BORDER)
204 					: BControlLook::B_ALL_BORDERS);
205 		}
206 
207 		if (fHasBattery) {
208 			if (percent <= kLowBatteryPercentage)
209 				base.set_to(180, 0, 0);
210 			else if (percent <= kNoteBatteryPercentage)
211 				base.set_to(200, 140, 0);
212 			else
213 				base.set_to(20, 180, 0);
214 
215 			rect.right = rect.left + rect.Width() * percent / 100.0;
216 
217 			if (be_control_look != NULL) {
218 				be_control_look->DrawButtonBackground(this, rect, rect, base,
219 					fHasBattery ? 0 : BControlLook::B_DISABLED);
220 			} else
221 				FillRect(rect);
222 		}
223 	}
224 
225 	SetHighColor(0, 0, 0);
226 }
227 
228 
229 void
230 PowerStatusView::Draw(BRect updateRect)
231 {
232 	bool drawBackground = Parent() == NULL
233 		|| (Parent()->Flags() & B_DRAW_ON_CHILDREN) == 0;
234 	if (drawBackground)
235 		FillRect(updateRect, B_SOLID_LOW);
236 
237 	float aspect = Bounds().Width() / Bounds().Height();
238 	bool below = aspect <= 1.0f;
239 
240 	font_height fontHeight;
241 	GetFontHeight(&fontHeight);
242 	float baseLine = ceilf(fontHeight.ascent);
243 
244 	char text[64];
245 	_SetLabel(text, sizeof(text));
246 
247 	float textHeight = ceilf(fontHeight.descent + fontHeight.ascent);
248 	float textWidth = StringWidth(text);
249 	bool showLabel = fShowLabel && text[0];
250 
251 	BRect iconRect;
252 
253 	if (fShowStatusIcon) {
254 		iconRect = Bounds();
255 		if (showLabel) {
256 			if (below)
257 				iconRect.bottom -= textHeight + 4;
258 			else
259 				iconRect.right -= textWidth + 4;
260 		}
261 
262 		// make a square
263 		iconRect.bottom = min_c(iconRect.bottom, iconRect.right);
264 		iconRect.right = iconRect.bottom;
265 
266 		if (iconRect.Width() + 1 >= kMinIconWidth
267 			&& iconRect.Height() + 1 >= kMinIconHeight) {
268 			_DrawBattery(iconRect);
269 		} else {
270 			// there is not enough space for the icon
271 			iconRect.Set(0, 0, -1, -1);
272 		}
273 	}
274 
275 	if (showLabel) {
276 		BPoint point(0, baseLine);
277 
278 		if (iconRect.IsValid()) {
279 			if (below) {
280 				point.x = (iconRect.Width() - textWidth) / 2;
281 				point.y += iconRect.Height() + 2;
282 			} else {
283 				point.x = iconRect.Width() + 2;
284 				point.y += (iconRect.Height() - textHeight) / 2;
285 			}
286 		} else {
287 			point.x = (Bounds().Width() - textWidth) / 2;
288 			point.y += (Bounds().Height() - textHeight) / 2;
289 		}
290 
291 		if (drawBackground)
292 			SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
293 		else {
294 			SetDrawingMode(B_OP_OVER);
295 			rgb_color c = Parent()->LowColor();
296 			if (c.red + c.green + c.blue > 128 * 3)
297 				SetHighColor(0, 0, 0);
298 			else
299 				SetHighColor(255, 255, 255);
300 		}
301 
302 		DrawString(text, point);
303 	}
304 }
305 
306 
307 void
308 PowerStatusView::_SetLabel(char* buffer, size_t bufferLength)
309 {
310 	if (bufferLength < 1)
311 		return;
312 
313 	buffer[0] = '\0';
314 
315 	if (!fShowLabel)
316 		return;
317 
318 	const char* open = "";
319 	const char* close = "";
320 	if (fOnline) {
321 		open = "(";
322 		close = ")";
323 	}
324 
325 	if (!fShowTime && fPercent >= 0) {
326 		snprintf(buffer, bufferLength, "%s%" B_PRId32 "%%%s", open, fPercent,
327 			close);
328 	} else if (fShowTime && fTimeLeft >= 0) {
329 		snprintf(buffer, bufferLength, "%s%" B_PRId32 ":%02" B_PRId32 "%s",
330 			open, fTimeLeft / 3600, (fTimeLeft / 60) % 60, close);
331 	}
332 }
333 
334 
335 
336 void
337 PowerStatusView::Update(bool force)
338 {
339 	int32 previousPercent = fPercent;
340 	time_t previousTimeLeft = fTimeLeft;
341 	bool wasOnline = fOnline;
342 	bool hadBattery = fHasBattery;
343 
344 	_GetBatteryInfo(fBatteryID, &fBatteryInfo);
345 	fHasBattery = fBatteryInfo.full_capacity > 0;
346 
347 	if (fBatteryInfo.full_capacity > 0 && fHasBattery) {
348 		fPercent = (100 * fBatteryInfo.capacity) / fBatteryInfo.full_capacity;
349 		fOnline = (fBatteryInfo.state & BATTERY_DISCHARGING) == 0;
350 		fTimeLeft = fBatteryInfo.time_left;
351 	} else {
352 		fPercent = 0;
353 		fOnline = false;
354 		fTimeLeft = -1;
355 	}
356 
357 	if (fHasBattery && (fPercent <= 0 || fPercent > 100)) {
358 		// Just ignore this probe -- it obviously returned invalid values
359 		fPercent = previousPercent;
360 		fTimeLeft = previousTimeLeft;
361 		fOnline = wasOnline;
362 		fHasBattery = hadBattery;
363 		return;
364 	}
365 
366 	if (fInDeskbar) {
367 		// make sure the tray icon is large enough
368 		float width = fShowStatusIcon ? kMinIconWidth + 2 : 0;
369 
370 		if (fShowLabel) {
371 			char text[64];
372 			_SetLabel(text, sizeof(text));
373 
374 			if (text[0])
375 				width += ceilf(StringWidth(text)) + 4;
376 		} else {
377 			char text[256];
378 			const char* open = "";
379 			const char* close = "";
380 			if (fOnline) {
381 				open = "(";
382 				close = ")";
383 			}
384 			if (fHasBattery) {
385 				size_t length = snprintf(text, sizeof(text), "%s%" B_PRId32
386 					"%%%s", open, fPercent, close);
387 				if (fTimeLeft >= 0) {
388 					length += snprintf(text + length, sizeof(text) - length,
389 						"\n%" B_PRId32 ":%02" B_PRId32, fTimeLeft / 3600,
390 						(fTimeLeft / 60) % 60);
391 				}
392 
393 				const char* state = NULL;
394 				if ((fBatteryInfo.state & BATTERY_CHARGING) != 0)
395 					state = B_TRANSLATE("charging");
396 				else if ((fBatteryInfo.state & BATTERY_DISCHARGING) != 0)
397 					state = B_TRANSLATE("discharging");
398 
399 				if (state != NULL) {
400 					snprintf(text + length, sizeof(text) - length, "\n%s",
401 						state);
402 				}
403 			} else
404 				strcpy(text, B_TRANSLATE("no battery"));
405 			SetToolTip(text);
406 		}
407 		if (width == 0) {
408 			// make sure we're not going away completely
409 			width = 8;
410 		}
411 
412 		if (width != Bounds().Width())
413 			ResizeTo(width, Bounds().Height());
414 	}
415 
416 	if (force || wasOnline != fOnline
417 		|| (fShowTime && fTimeLeft != previousTimeLeft)
418 		|| (!fShowTime && fPercent != previousPercent)) {
419 		Invalidate();
420 	}
421 
422 	if (!fOnline && fHasBattery && previousPercent > kLowBatteryPercentage
423 			&& fPercent <= kLowBatteryPercentage) {
424 		_NotifyLowBattery();
425 	}
426 }
427 
428 
429 void
430 PowerStatusView::FromMessage(const BMessage* archive)
431 {
432 	bool value;
433 	if (archive->FindBool("show label", &value) == B_OK)
434 		fShowLabel = value;
435 	if (archive->FindBool("show icon", &value) == B_OK)
436 		fShowStatusIcon = value;
437 	if (archive->FindBool("show time", &value) == B_OK)
438 		fShowTime = value;
439 
440 	//Incase we have a bad saving and none are showed..
441 	if (!fShowLabel && !fShowStatusIcon)
442 		fShowLabel = true;
443 
444 	int32 intValue;
445 	if (archive->FindInt32("battery id", &intValue) == B_OK)
446 		fBatteryID = intValue;
447 }
448 
449 
450 status_t
451 PowerStatusView::ToMessage(BMessage* archive) const
452 {
453 	status_t status = archive->AddBool("show label", fShowLabel);
454 	if (status == B_OK)
455 		status = archive->AddBool("show icon", fShowStatusIcon);
456 	if (status == B_OK)
457 		status = archive->AddBool("show time", fShowTime);
458 	if (status == B_OK)
459 		status = archive->AddInt32("battery id", fBatteryID);
460 
461 	return status;
462 }
463 
464 
465 void
466 PowerStatusView::_GetBatteryInfo(int batteryID, battery_info* batteryInfo)
467 {
468 	if (batteryID >= 0) {
469 		fDriverInterface->GetBatteryInfo(batteryID, batteryInfo);
470 	} else {
471 		bool first = true;
472 		memset(batteryInfo, 0, sizeof(battery_info));
473 
474 		for (int i = 0; i < fDriverInterface->GetBatteryCount(); i++) {
475 			battery_info info;
476 			fDriverInterface->GetBatteryInfo(i, &info);
477 
478 			if (info.full_capacity <= 0)
479 				continue;
480 
481 			if (first) {
482 				*batteryInfo = info;
483 				first = false;
484 			} else {
485 				batteryInfo->state |= info.state;
486 				batteryInfo->capacity += info.capacity;
487 				batteryInfo->full_capacity += info.full_capacity;
488 				batteryInfo->time_left += info.time_left;
489 			}
490 		}
491 	}
492 }
493 
494 
495 void
496 PowerStatusView::_NotifyLowBattery()
497 {
498 	BBitmap* bitmap = NULL;
499 	BResources resources;
500 	resources.SetToImage((void*)&instantiate_deskbar_item);
501 
502 	if (resources.InitCheck() == B_OK) {
503 		size_t resourceSize = 0;
504 		const void* resourceData = resources.LoadResource(
505 			B_VECTOR_ICON_TYPE, fHasBattery
506 				? "battery_low" : "battery_critical", &resourceSize);
507 		if (resourceData != NULL) {
508 			BMemoryIO memoryIO(resourceData, resourceSize);
509 			bitmap = BTranslationUtils::GetBitmap(&memoryIO);
510 		}
511 	}
512 
513 	BNotification notification(
514 		fHasBattery ? B_INFORMATION_NOTIFICATION : B_ERROR_NOTIFICATION);
515 
516 	if (fHasBattery) {
517 		notification.SetTitle(B_TRANSLATE("Battery low"));
518 		notification.SetContent(B_TRANSLATE(
519 			"The battery level is getting low, please plug in the device."));
520 	} else {
521 		notification.SetTitle(B_TRANSLATE("Battery critical"));
522 		notification.SetContent(B_TRANSLATE(
523 			"The battery level is critical, please plug in the device "
524 			"immediately."));
525 	}
526 
527 	notification.SetIcon(bitmap);
528 	notification.Send();
529 	delete bitmap;
530 }
531 
532 
533 // #pragma mark - Replicant view
534 
535 
536 PowerStatusReplicant::PowerStatusReplicant(BRect frame, int32 resizingMode,
537 	bool inDeskbar)
538 	:
539 	PowerStatusView(NULL, frame, resizingMode, -1, inDeskbar)
540 {
541 	_Init();
542 	_LoadSettings();
543 
544 	if (!inDeskbar) {
545 		// we were obviously added to a standard window - let's add a dragger
546 		frame.OffsetTo(B_ORIGIN);
547 		frame.top = frame.bottom - 7;
548 		frame.left = frame.right - 7;
549 		BDragger* dragger = new BDragger(frame, this,
550 			B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
551 		AddChild(dragger);
552 	} else
553 		Update();
554 }
555 
556 
557 PowerStatusReplicant::PowerStatusReplicant(BMessage* archive)
558 	:
559 	PowerStatusView(archive)
560 {
561 	_Init();
562 	_LoadSettings();
563 }
564 
565 
566 PowerStatusReplicant::~PowerStatusReplicant()
567 {
568 	if (fMessengerExist)
569 		delete fExtWindowMessenger;
570 
571 	fDriverInterface->StopWatching(this);
572 	fDriverInterface->Disconnect();
573 	fDriverInterface->ReleaseReference();
574 
575 	_SaveSettings();
576 }
577 
578 
579 PowerStatusReplicant*
580 PowerStatusReplicant::Instantiate(BMessage* archive)
581 {
582 	if (!validate_instantiation(archive, "PowerStatusReplicant"))
583 		return NULL;
584 
585 	return new PowerStatusReplicant(archive);
586 }
587 
588 
589 status_t
590 PowerStatusReplicant::Archive(BMessage* archive, bool deep) const
591 {
592 	status_t status = PowerStatusView::Archive(archive, deep);
593 	if (status == B_OK)
594 		status = archive->AddString("add_on", kSignature);
595 	if (status == B_OK)
596 		status = archive->AddString("class", "PowerStatusReplicant");
597 
598 	return status;
599 }
600 
601 
602 void
603 PowerStatusReplicant::MessageReceived(BMessage *message)
604 {
605 	switch (message->what) {
606 		case kMsgToggleLabel:
607 			if (fShowStatusIcon)
608 				fShowLabel = !fShowLabel;
609 			else
610 				fShowLabel = true;
611 
612 			Update(true);
613 			break;
614 
615 		case kMsgToggleTime:
616 			fShowTime = !fShowTime;
617 			Update(true);
618 			break;
619 
620 		case kMsgToggleStatusIcon:
621 			if (fShowLabel)
622 				fShowStatusIcon = !fShowStatusIcon;
623 			else
624 				fShowStatusIcon = true;
625 
626 			Update(true);
627 			break;
628 
629 		case kMsgToggleExtInfo:
630 			_OpenExtendedWindow();
631 			break;
632 
633 		case B_ABOUT_REQUESTED:
634 			_AboutRequested();
635 			break;
636 
637 		case B_QUIT_REQUESTED:
638 			_Quit();
639 			break;
640 
641 		default:
642 			PowerStatusView::MessageReceived(message);
643 	}
644 }
645 
646 
647 void
648 PowerStatusReplicant::MouseDown(BPoint point)
649 {
650 	BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
651 	menu->SetFont(be_plain_font);
652 
653 	BMenuItem* item;
654 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Show text label"),
655 		new BMessage(kMsgToggleLabel)));
656 	if (fShowLabel)
657 		item->SetMarked(true);
658 	menu->AddItem(item = new BMenuItem(B_TRANSLATE("Show status icon"),
659 		new BMessage(kMsgToggleStatusIcon)));
660 	if (fShowStatusIcon)
661 		item->SetMarked(true);
662 	menu->AddItem(new BMenuItem(!fShowTime ? B_TRANSLATE("Show time") :
663 	B_TRANSLATE("Show percent"),
664 		new BMessage(kMsgToggleTime)));
665 
666 	menu->AddSeparatorItem();
667 	menu->AddItem(new BMenuItem(B_TRANSLATE("Battery info" B_UTF8_ELLIPSIS),
668 		new BMessage(kMsgToggleExtInfo)));
669 
670 	menu->AddSeparatorItem();
671 	menu->AddItem(new BMenuItem(B_TRANSLATE("About" B_UTF8_ELLIPSIS),
672 		new BMessage(B_ABOUT_REQUESTED)));
673 	menu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
674 		new BMessage(B_QUIT_REQUESTED)));
675 	menu->SetTargetForItems(this);
676 
677 	ConvertToScreen(&point);
678 	menu->Go(point, true, false, true);
679 }
680 
681 
682 void
683 PowerStatusReplicant::_AboutRequested()
684 {
685 	BAboutWindow* window = new BAboutWindow(
686 		B_TRANSLATE_SYSTEM_NAME("PowerStatus"), kSignature);
687 
688 	const char* authors[] = {
689 		"Axel Dörfler",
690 		"Alexander von Gluck",
691 		"Clemens Zeidler",
692 		NULL
693 	};
694 
695 	window->AddCopyright(2006, "Haiku, Inc.");
696 	window->AddAuthors(authors);
697 
698 	window->Show();
699 }
700 
701 
702 void
703 PowerStatusReplicant::_Init()
704 {
705 	fDriverInterface = new ACPIDriverInterface;
706 	if (fDriverInterface->Connect() != B_OK) {
707 		delete fDriverInterface;
708 		fDriverInterface = new APMDriverInterface;
709 		if (fDriverInterface->Connect() != B_OK) {
710 			fprintf(stderr, "No power interface found.\n");
711 			_Quit();
712 		}
713 	}
714 
715 	fExtendedWindow = NULL;
716 	fMessengerExist = false;
717 	fExtWindowMessenger = NULL;
718 
719 	fDriverInterface->StartWatching(this);
720 }
721 
722 
723 void
724 PowerStatusReplicant::_Quit()
725 {
726 	if (fInDeskbar) {
727 		BDeskbar deskbar;
728 		deskbar.RemoveItem(kDeskbarItemName);
729 	} else
730 		be_app->PostMessage(B_QUIT_REQUESTED);
731 }
732 
733 
734 status_t
735 PowerStatusReplicant::_GetSettings(BFile& file, int mode)
736 {
737 	BPath path;
738 	status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path,
739 		(mode & O_ACCMODE) != O_RDONLY);
740 	if (status != B_OK)
741 		return status;
742 
743 	path.Append("PowerStatus settings");
744 
745 	return file.SetTo(path.Path(), mode);
746 }
747 
748 
749 void
750 PowerStatusReplicant::_LoadSettings()
751 {
752 	fShowLabel = false;
753 
754 	BFile file;
755 	if (_GetSettings(file, B_READ_ONLY) != B_OK)
756 		return;
757 
758 	BMessage settings;
759 	if (settings.Unflatten(&file) < B_OK)
760 		return;
761 
762 	FromMessage(&settings);
763 }
764 
765 
766 void
767 PowerStatusReplicant::_SaveSettings()
768 {
769 	BFile file;
770 	if (_GetSettings(file, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE) != B_OK)
771 		return;
772 
773 	BMessage settings('pwst');
774 	ToMessage(&settings);
775 
776 	ssize_t size = 0;
777 	settings.Flatten(&file, &size);
778 }
779 
780 
781 void
782 PowerStatusReplicant::_OpenExtendedWindow()
783 {
784 	if (!fExtendedWindow) {
785 		fExtendedWindow = new ExtendedInfoWindow(fDriverInterface);
786 		fExtWindowMessenger = new BMessenger(NULL, fExtendedWindow);
787 		fExtendedWindow->Show();
788 		return;
789 	}
790 
791 	BMessage msg(B_SET_PROPERTY);
792 	msg.AddSpecifier("Hidden", int32(0));
793 	if (fExtWindowMessenger->SendMessage(&msg) == B_BAD_PORT_ID) {
794 		fExtendedWindow = new ExtendedInfoWindow(fDriverInterface);
795 		if (fMessengerExist)
796 			delete fExtWindowMessenger;
797 		fExtWindowMessenger = new BMessenger(NULL, fExtendedWindow);
798 		fMessengerExist = true;
799 		fExtendedWindow->Show();
800 	} else
801 		fExtendedWindow->Activate();
802 
803 }
804 
805 
806 //	#pragma mark -
807 
808 
809 extern "C" _EXPORT BView*
810 instantiate_deskbar_item(void)
811 {
812 	return new PowerStatusReplicant(BRect(0, 0, 15, 15), B_FOLLOW_NONE, true);
813 }
814