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