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