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