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