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