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