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