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