Add a ACPI battery driver interface to the PowerStatus app. If there is anyone with a working APM please test if its still working!

TODO:
- Get along with the Layout engine, the extended info window looks "no very nice".
- Reading the battery status takes too long so put it into a thread or cache it.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31484 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler
2009-07-09 17:16:31 +00:00
parent 34fc10ad1f
commit 6aed176c09
13 changed files with 1445 additions and 227 deletions
@@ -0,0 +1,240 @@
/*
* Copyright 2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#include "ACPIDriverInterface.h"
#include <stdio.h>
#include <Autolock.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>
RateBuffer::RateBuffer()
:
fPosition(0),
fSize(kRateBufferSize),
fCurrentSize(0)
{
}
void
RateBuffer::AddRate(int32 rate)
{
fRateBuffer[fPosition] = rate;
fPosition ++;
if (fPosition >= fSize)
fPosition = 0;
if (fCurrentSize < fSize)
fCurrentSize ++;
}
int32
RateBuffer::GetMeanRate()
{
int mean = 0;
for (int i = 0; i < fCurrentSize; i++) {
mean += fRateBuffer[i];
}
if (fCurrentSize == 0)
return -1;
return mean / fCurrentSize;
}
Battery::Battery(int driverHandler)
:
fDriverHandler(driverHandler)
{
_Init();
}
Battery::~Battery()
{
close(fDriverHandler);
}
status_t
Battery::InitCheck()
{
return fInitStatus;
}
status_t
Battery::GetBatteryInfo(battery_info* info)
{
acpi_battery_info acpiInfo;
status_t status;
status = ioctl(fDriverHandler, GET_BATTERY_INFO, &acpiInfo,
sizeof(acpi_battery_info));
if (status != B_OK)
return status;
info->state = acpiInfo.state;
info->current_rate = acpiInfo.current_rate;
info->capacity = acpiInfo.capacity;
info->full_capacity = fExtendedBatteryInfo.last_full_charge;
fRateBuffer.AddRate(acpiInfo.current_rate);
if (acpiInfo.current_rate > 0)
info->time_left = 3600 * acpiInfo.capacity / fRateBuffer.GetMeanRate();
else
info->time_left = -1;
return B_OK;
}
status_t
Battery::GetExtendedBatteryInfo(acpi_extended_battery_info* info)
{
status_t status;
status = ioctl(fDriverHandler, GET_EXTENDED_BATTERY_INFO, info,
sizeof(acpi_extended_battery_info));
return status;
}
void
Battery::_Init()
{
uint32 magicId = 0;
fInitStatus = ioctl(fDriverHandler, IDENTIFY_DEVICE, &magicId,
sizeof(uint32));
if (fInitStatus != B_OK)
return;
fInitStatus = ioctl(fDriverHandler, GET_EXTENDED_BATTERY_INFO,
&fExtendedBatteryInfo, sizeof(acpi_extended_battery_info));
if (fInitStatus != B_OK)
return;
acpi_battery_info info;
fInitStatus = ioctl(fDriverHandler, GET_BATTERY_INFO, &info,
sizeof(acpi_battery_info));
if (fInitStatus != B_OK)
return;
printf("ACPI driver found\n");
}
ACPIDriverInterface::~ACPIDriverInterface()
{
for (int i = 0; i < fDriverList.CountItems(); i++)
delete fDriverList.ItemAt(i);
}
const char* kDriverDir = "/dev/power";
status_t
ACPIDriverInterface::Connect()
{
printf("ACPI connect\n");
return _FindDrivers(kDriverDir);
}
status_t
ACPIDriverInterface::GetBatteryInfo(battery_info* info, int32 index)
{
BAutolock autolock(fBatteryStatusLock);
if (index < 0 || index >= fDriverList.CountItems())
return B_ERROR;
status_t status;
status = fDriverList.ItemAt(index)->GetBatteryInfo(info);
return status;
}
status_t
ACPIDriverInterface::GetExtendedBatteryInfo(acpi_extended_battery_info* info,
int32 index)
{
BAutolock autolock(fBatteryStatusLock);
if (index < 0 || index >= fDriverList.CountItems())
return B_ERROR;
status_t status;
status = fDriverList.ItemAt(index)->GetExtendedBatteryInfo(info);
return status;
}
int32
ACPIDriverInterface::GetBatteryCount()
{
return fDriverList.CountItems();
}
void
ACPIDriverInterface::_WatchPowerStatus()
{
const bigtime_t kUpdateInterval = 2000000;
// every two seconds
while (atomic_get(&fIsWatching) > 0) {
Broadcast(kMsgUpdate);
snooze(kUpdateInterval);
}
}
status_t
ACPIDriverInterface::_FindDrivers(const char* path)
{
BDirectory dir(path);
BEntry entry;
status_t status = B_ERROR;
while (dir.GetNextEntry(&entry) == B_OK) {
BPath path;
entry.GetPath(&path);
if (entry.IsDirectory()) {
if (_FindDrivers(path.Path()) == B_OK)
return B_OK;
}
else {
int32 handler = open(path.Path(), O_RDWR);
if (handler >= 0) {
printf("try %s\n", path.Path());
Battery* battery = new Battery(handler);
if (battery->InitCheck() == B_OK) {
fDriverList.AddItem(battery);
status = B_OK;
}
else
delete battery;
}
}
}
return status;
}
@@ -0,0 +1,80 @@
/*
* Copyright 2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#ifndef ACPI_DRIVER_INTERFACE_H
#define ACPI_DRIVER_INTERFACE_H
#include "DriverInterface.h"
#include <Locker.h>
#include <ObjectList.h>
const int8 kRateBufferSize = 10;
class RateBuffer
{
public:
RateBuffer();
void AddRate(int32 rate);
int32 GetMeanRate();
private:
int32 fRateBuffer[kRateBufferSize];
int8 fPosition;
int8 fSize;
int8 fCurrentSize;
};
class Battery
{
public:
Battery(int driverHandler);
~Battery();
status_t InitCheck();
status_t GetBatteryInfo(battery_info* info);
status_t GetExtendedBatteryInfo(
acpi_extended_battery_info* info);
private:
void _Init();
int fDriverHandler;
status_t fInitStatus;
acpi_extended_battery_info fExtendedBatteryInfo;
RateBuffer fRateBuffer;
};
class ACPIDriverInterface : public PowerStatusDriverInterface
{
public:
virtual ~ACPIDriverInterface();
virtual status_t Connect();
virtual status_t GetBatteryInfo(battery_info* info, int32 index);
virtual status_t GetExtendedBatteryInfo(
acpi_extended_battery_info* info, int32 index);
virtual int32 GetBatteryCount();
protected:
virtual void _WatchPowerStatus();
virtual status_t _FindDrivers(const char* path);
BObjectList<Battery> fDriverList;
BLocker fBatteryStatusLock;
};
#endif
+140
View File
@@ -0,0 +1,140 @@
/*
* Copyright 2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#include "APMDriverInterface.h"
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
# include <arch/x86/apm_defs.h>
# include <generic_syscall_defs.h>
# include <syscalls.h>
// temporary, as long as there is no real power state API
#endif
const bigtime_t kUpdateInterval = 2000000;
// every two seconds
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
// definitions for the APM driver available for BeOS
enum {
APM_CONTROL = B_DEVICE_OP_CODES_END + 1,
APM_DUMP_POWER_STATUS,
APM_BIOS_CALL,
APM_SET_SAFETY
};
#define BIOS_APM_GET_POWER_STATUS 0x530a
#endif
APMDriverInterface::~APMDriverInterface()
{
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
close(fDevice);
#endif
}
status_t
APMDriverInterface::Connect()
{
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
uint32 version = 0;
status_t status = _kern_generic_syscall(APM_SYSCALLS, B_SYSCALL_INFO,
&version, sizeof(version));
if (status == B_OK) {
battery_info info;
status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO,
&info, sizeof(battery_info));
}
return status;
#else
fDevice = open("/dev/misc/apm", O_RDONLY);
if (fDevice < 0) {
return B_ERROR;
}
return B_OK;
#endif
}
status_t
APMDriverInterface::GetBatteryInfo(battery_info* info, int32 index)
{
if (index != 0)
return B_BAD_VALUE;
info->current_rate = -1;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
// TODO: retrieve data from APM kernel interface
apm_battery_info apmInfo;
status_t status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO,
&apmInfo, sizeof(apm_battery_info));
if (status == B_OK) {
info->state = apmInfo.online ? BATTERY_CHARGING : BATTERY_DISCHARGING;
info->capacity = apmInfo.percent;
info->full_capacity = 100;
info->time_left = apmInfo.time_left;
}
return status;
#else
if (fDevice < 0)
return B_ERROR;
uint16 regs[6] = {0, 0, 0, 0, 0, 0};
regs[0] = BIOS_APM_GET_POWER_STATUS;
regs[1] = 0x1;
if (ioctl(fDevice, APM_BIOS_CALL, regs) == 0) {
bool online = (regs[1] >> 8) != 0 && (regs[1] >> 8) != 2;
info->state = online ? BATTERY_CHARGING : BATTERY_DISCHARGING;
info->capacity = regs[2] & 255;
if (info->capacity > 100)
info->capacity = -1;
info->full_capacity = 100;
info->time_left = info->capacity >= 0 ? regs[3] : -1;
if (info->time_left > 0xffff)
info->time_left = -1;
else if (info->time_left & 0x8000)
info->time_left = (info->time_left & 0x7fff) * 60;
}
return B_OK;
#endif
}
status_t
APMDriverInterface::GetExtendedBatteryInfo(acpi_extended_battery_info* info,
int32 index)
{
return B_ERROR;
}
int32
APMDriverInterface::GetBatteryCount()
{
return 1;
}
void
APMDriverInterface::_WatchPowerStatus()
{
while (atomic_get(&fIsWatching) > 0) {
Broadcast(kMsgUpdate);
snooze(kUpdateInterval);
}
}
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright 2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#ifndef APM_DRIVER_INTERFACE_H
#define APM_DRIVER_INTERFACE_H
#include "DriverInterface.h"
class APMDriverInterface : public PowerStatusDriverInterface
{
public:
virtual ~APMDriverInterface();
virtual status_t Connect();
virtual status_t GetBatteryInfo(battery_info* info, int32 index);
virtual status_t GetExtendedBatteryInfo(acpi_extended_battery_info* info,
int32 index);
virtual int32 GetBatteryCount();
protected:
virtual void _WatchPowerStatus();
private:
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
int fDevice;
#endif
};
#endif
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#include "DriverInterface.h"
#include <Autolock.h>
#include <Messenger.h>
Monitor::~Monitor()
{
}
status_t
Monitor::StartWatching(BHandler* target)
{
if (fWatcherList.HasItem(target))
return B_ERROR;
fWatcherList.AddItem(target);
return B_OK;
}
status_t
Monitor::StopWatching(BHandler* target)
{
return fWatcherList.RemoveItem(target);
}
void
Monitor::Broadcast(uint32 message)
{
for (int i = 0; i < fWatcherList.CountItems(); i++)
{
BMessenger messenger(fWatcherList.ItemAt(i));
messenger.SendMessage(message);
}
}
PowerStatusDriverInterface::PowerStatusDriverInterface()
:
fIsWatching(0),
fThreadId(-1)
{
}
PowerStatusDriverInterface::~PowerStatusDriverInterface()
{
}
#include <stdio.h>
status_t
PowerStatusDriverInterface::StartWatching(BHandler* target)
{
BAutolock autolock(fListLocker);
status_t status = Monitor::StartWatching(target);
if (status != B_OK)
return status;
if (fThreadId > 0)
return B_OK;
printf("spawn\n");
fThreadId = spawn_thread(&_ThreadWatchPowerFunction, "PowerStatusThread",
B_LOW_PRIORITY, this);
if (fThreadId >= 0) {
atomic_set(&fIsWatching, 1);
status = resume_thread(fThreadId);
}
else
return fThreadId;
if (status != B_OK && fWatcherList.CountItems() == 0) {
atomic_set(&fIsWatching, 0);
}
return status;
}
status_t
PowerStatusDriverInterface::StopWatching(BHandler* target)
{
BAutolock autolock(fListLocker);
if (fThreadId < 0)
return B_BAD_VALUE;
status_t status;
if (fWatcherList.CountItems() == 1) {
atomic_set(&fIsWatching, 0);
status = wait_for_thread(fThreadId, &status);
fThreadId = -1;
}
return Monitor::StopWatching(target);
}
void
PowerStatusDriverInterface::Disconnect()
{
atomic_set(&fIsWatching, 0);
status_t status;
wait_for_thread(fThreadId, &status);
fThreadId = -1;
}
int32
PowerStatusDriverInterface::_ThreadWatchPowerFunction(void* data)
{
PowerStatusDriverInterface* that = (PowerStatusDriverInterface*)data;
that->_WatchPowerStatus();
return 0;
}
+80
View File
@@ -0,0 +1,80 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#ifndef DRIVER_INTERFACE_H
#define DRIVER_INTERFACE_H
#include <Locker.h>
#include <ObjectList.h>
#include <Handler.h>
#include "device/power_managment.h"
typedef BObjectList<BHandler> WatcherList;
const uint32 kMsgUpdate = 'updt';
struct battery_info
{
int8 state;
int32 capacity;
int32 full_capacity;
time_t time_left;
int32 current_rate;
};
/*! Handle a list of watcher and broadcast a messages to them. */
class Monitor
{
public:
virtual ~Monitor();
virtual status_t StartWatching(BHandler* target);
virtual status_t StopWatching(BHandler* target);
virtual void Broadcast(uint32 message);
protected:
WatcherList fWatcherList;
};
class PowerStatusDriverInterface : public Monitor
{
public:
PowerStatusDriverInterface();
~PowerStatusDriverInterface();
virtual status_t StartWatching(BHandler* target);
virtual status_t StopWatching(BHandler* target);
virtual status_t Connect() = 0;
virtual void Disconnect();
virtual status_t GetBatteryInfo(battery_info* status, int32 index) = 0;
virtual status_t GetExtendedBatteryInfo(acpi_extended_battery_info* info,
int32 index) = 0;
virtual int32 GetBatteryCount() = 0;
protected:
virtual void _WatchPowerStatus() = 0;
vint32 fIsWatching;
private:
static int32 _ThreadWatchPowerFunction(void* data);
thread_id fThreadId;
BLocker fListLocker;
};
#endif
+306
View File
@@ -0,0 +1,306 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#include "ExtendedInfoWindow.h"
#include <Box.h>
#include <GroupLayout.h>
#include <GroupView.h>
#include <SpaceLayoutItem.h>
#include <String.h>
BatteryInfoView::BatteryInfoView(BRect frame, int32 resizingMode)
:
BView(frame, "battery info view", resizingMode, B_WILL_DRAW |
B_FULL_UPDATE_ON_RESIZE)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
void
BatteryInfoView::Update(battery_info& info, acpi_extended_battery_info& extInfo)
{
fBatteryInfo = info;
fBatteryExtendedInfo = extInfo;
}
void
BatteryInfoView::Draw(BRect updateRect)
{
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
BString powerUnit;
BString rateUnit;
switch (fBatteryExtendedInfo.power_unit) {
case 0:
powerUnit = " mWh";
rateUnit = " mW";
break;
case 1:
powerUnit = " mAh";
rateUnit = " mA";
break;
}
BString text;
if (fBatteryInfo.state & BATTERY_CHARGING)
text = "Battery charging";
else if (fBatteryInfo.state & BATTERY_DISCHARGING)
text = "Battery discharging";
else if (fBatteryInfo.state & BATTERY_CRITICAL_STATE)
text = "Empty Battery Slot";
else
text = "Battery unused";
BPoint point(10, 10);
int textHeight = 15;
int space = textHeight + 5;
DrawString(text.String(), point);
point.y += space;
text = "Capacity: ";
text << fBatteryInfo.capacity;
text << powerUnit;
DrawString(text.String(), point);
point.y += space;
text = "Last full Charge: ";
text << fBatteryInfo.full_capacity;
text << powerUnit;
DrawString(text.String(), point);
point.y += space;
text = "Current Rate: ";
text << fBatteryInfo.current_rate;
text << rateUnit;
DrawString(text.String(), point);
point.y += space;
point.y += space;
text = "Design Capacity: ";
text << fBatteryExtendedInfo.design_capacity;
text << powerUnit;
DrawString(text.String(), point);
point.y += space;
text = "Technology: ";
text << fBatteryExtendedInfo.technology;
DrawString(text.String(), point);
point.y += space;
text = "Design Voltage: ";
text << fBatteryExtendedInfo.design_voltage;
text << " mV";
DrawString(text.String(), point);
point.y += space;
text = "Design Capacity Warning: ";
text << fBatteryExtendedInfo.design_capacity_warning;
text << powerUnit;
DrawString(text.String(), point);
point.y += space;
text = "Design Capacity low Warning: ";
text << fBatteryExtendedInfo.design_capacity_low;
text << powerUnit;
DrawString(text.String(), point);
point.y += space;
text = "Capacity Granularity 1: ";
text << fBatteryExtendedInfo.capacity_granularity_1;
DrawString(text.String(), point);
point.y += space;
text = "Capacity Granularity 2: ";
text << fBatteryExtendedInfo.capacity_granularity_2;
DrawString(text.String(), point);
point.y += space;
text = "Model Number: ";
text << fBatteryExtendedInfo.model_number;
DrawString(text.String(), point);
point.y += space;
text = "Serial number: ";
text << fBatteryExtendedInfo.serial_number;
DrawString(text.String(), point);
point.y += space;
text = "Type: ";
text += fBatteryExtendedInfo.type;
DrawString(text.String(), point);
point.y += space;
text = "OEM Info: ";
text += fBatteryExtendedInfo.oem_info;
DrawString(text.String(), point);
point.y += space;
}
ExtPowerStatusView::ExtPowerStatusView(PowerStatusDriverInterface* interface,
BRect frame, int32 resizingMode, int batteryId,
ExtendedInfoWindow* window)
:
PowerStatusView(interface, frame, resizingMode, batteryId),
fExtendedInfoWindow(window),
fBatteryInfoView(window->GetExtendedBatteryInfoView()),
fSelected(false)
{
}
void
ExtPowerStatusView::Draw(BRect updateRect)
{
if (fSelected) {
SetLowColor(102, 152, 203);
SetHighColor(102, 152, 203);
FillRect(updateRect);
}
else {
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
FillRect(updateRect);
}
PowerStatusView::Draw(updateRect);
}
void
ExtPowerStatusView::MouseDown(BPoint where)
{
if (!fSelected) {
fSelected = true;
_Update(true);
fExtendedInfoWindow->BatterySelected(this);
}
}
void
ExtPowerStatusView::Select(bool select)
{
fSelected = select;
_Update(true);
}
bool
ExtPowerStatusView::IsValid()
{
if (fBatteryInfo.state & BATTERY_CRITICAL_STATE)
return false;
return true;
}
void
ExtPowerStatusView::_Update(bool force)
{
PowerStatusView::_Update(force);
if (!fSelected)
return;
acpi_extended_battery_info extInfo;
fDriverInterface->GetExtendedBatteryInfo(&extInfo, fBatteryId);
fBatteryInfoView->Update(fBatteryInfo, extInfo);
fBatteryInfoView->Invalidate();
}
ExtendedInfoWindow::ExtendedInfoWindow(PowerStatusDriverInterface* interface)
:
BWindow(BRect(100, 150, 500, 500), "Extended Battery Info", B_TITLED_WINDOW,
B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS),
fDriverInterface(interface),
fSelectedView(NULL)
{
BView *view = new BView(Bounds(), "view", B_FOLLOW_ALL, 0);
view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(view);
BGroupLayout* mainLayout = new BGroupLayout(B_VERTICAL);
mainLayout->SetSpacing(10);
mainLayout->SetInsets(10, 10, 10, 10);
view->SetLayout(mainLayout);
BRect rect = Bounds();
rect.InsetBy(5, 5);
BBox *infoBox = new BBox(rect, "Power Status Box");
infoBox->SetLabel("Battery Info");
BGroupLayout* infoLayout = new BGroupLayout(B_HORIZONTAL);
infoLayout->SetInsets(10, infoBox->TopBorderOffset() * 2 + 10, 10, 10);
infoLayout->SetSpacing(10);
infoBox->SetLayout(infoLayout);
mainLayout->AddView(infoBox);
BGroupView* batteryView = new BGroupView(B_VERTICAL);
batteryView->GroupLayout()->SetSpacing(10);
infoLayout->AddView(batteryView);
fBatteryInfoView = new BatteryInfoView(BRect(0, 0, 270, 310), B_FOLLOW_ALL);
BGroupLayout* batteryLayout = batteryView->GroupLayout();
BRect batteryRect(0, 0, 50, 30);
for (int i = 0; i < interface->GetBatteryCount(); i++) {
ExtPowerStatusView* view = new ExtPowerStatusView(interface,
batteryRect, B_FOLLOW_ALL, i, this);
batteryLayout->AddView(view);
fBatteryViewList.AddItem(view);
fDriverInterface->StartWatching(view);
if (view->IsValid())
fSelectedView = view;
}
batteryLayout->AddItem(BSpaceLayoutItem::CreateGlue());
infoLayout->AddView(fBatteryInfoView, 20);
if (!fSelectedView && fBatteryViewList.CountItems() > 0)
fSelectedView = fBatteryViewList.ItemAt(0);
fSelectedView->Select();
BSize size = mainLayout->PreferredSize();
ResizeTo(size.width, size.height);
}
ExtendedInfoWindow::~ExtendedInfoWindow()
{
for (int i = 0; i < fBatteryViewList.CountItems(); i++) {
fDriverInterface->StopWatching(fBatteryViewList.ItemAt(i));
}
}
BatteryInfoView*
ExtendedInfoWindow::GetExtendedBatteryInfoView()
{
return fBatteryInfoView;
}
void
ExtendedInfoWindow::BatterySelected(ExtPowerStatusView* view)
{
if (fSelectedView) {
fSelectedView->Select(false);
fSelectedView->Invalidate();
}
fSelectedView = view;
}
+84
View File
@@ -0,0 +1,84 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Clemens Zeidler, [email protected]
*/
#ifndef EXTENDED_INFO_WINDOW_H
#define EXTENDED_INFO_WINDOW_H
#include <ObjectList.h>
#include <StringView.h>
#include <View.h>
#include <Window.h>
#include "DriverInterface.h"
#include "PowerStatusView.h"
class BatteryInfoView : public BView
{
public:
BatteryInfoView(BRect frame, int32 resizingMode);
virtual void Update(battery_info& info,
acpi_extended_battery_info& extInfo);
virtual void Draw(BRect updateRect);
private:
battery_info fBatteryInfo;
acpi_extended_battery_info fBatteryExtendedInfo;
};
class ExtendedInfoWindow;
class ExtPowerStatusView : public PowerStatusView
{
public:
ExtPowerStatusView(PowerStatusDriverInterface* interface,
BRect frame, int32 resizingMode, int batteryId,
ExtendedInfoWindow* window);
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
virtual void Select(bool select = true);
// return true if it battery is in a none critical state
virtual bool IsValid();
protected:
virtual void _Update(bool force = false);
private:
ExtendedInfoWindow* fExtendedInfoWindow;
BatteryInfoView* fBatteryInfoView;
bool fSelected;
};
class ExtendedInfoWindow : public BWindow
{
public:
ExtendedInfoWindow(PowerStatusDriverInterface* interface);
~ExtendedInfoWindow();
BatteryInfoView* GetExtendedBatteryInfoView();
void BatterySelected(ExtPowerStatusView* view);
private:
PowerStatusDriverInterface* fDriverInterface;
BObjectList<ExtPowerStatusView> fBatteryViewList;
BatteryInfoView* fBatteryInfoView;
ExtPowerStatusView* fSelectedView;
};
#endif
+4
View File
@@ -6,6 +6,10 @@ UsePrivateHeaders shared ;
UsePrivateSystemHeaders ;
Application PowerStatus :
ACPIDriverInterface.cpp
APMDriverInterface.cpp
DriverInterface.cpp
ExtendedInfoWindow.cpp
PowerStatusWindow.cpp
PowerStatusView.cpp
PowerStatus.cpp
+1
View File
@@ -12,4 +12,5 @@
extern const char* kSignature;
extern const char* kDeskbarItemName;
#endif // POWER_STATUS_H
+288 -209
View File
@@ -4,19 +4,13 @@
*
* Authors:
* Axel Dörfler, [email protected]
* Clemens Zeidler, [email protected]
*/
#include "PowerStatusView.h"
#include "PowerStatus.h"
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
# include <arch/x86/apm_defs.h>
# include <generic_syscall_defs.h>
# include <syscalls.h>
// temporary, as long as there is no real power state API
#endif
#include <Alert.h>
#include <Application.h>
#include <Deskbar.h>
@@ -32,52 +26,34 @@
#include <string.h>
#include <unistd.h>
#include "ACPIDriverInterface.h"
#include "APMDriverInterface.h"
#include "ExtendedInfoWindow.h"
extern "C" _EXPORT BView *instantiate_deskbar_item(void);
const uint32 kMsgUpdate = 'updt';
const uint32 kMsgToggleLabel = 'tglb';
const uint32 kMsgToggleTime = 'tgtm';
const uint32 kMsgToggleStatusIcon = 'tgsi';
const uint32 kMsgToggleExtInfo = 'texi';
const uint32 kMinIconWidth = 16;
const uint32 kMinIconHeight = 16;
const bigtime_t kUpdateInterval = 2000000;
// every two seconds
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
// definitions for the APM driver available for BeOS
enum {
APM_CONTROL = B_DEVICE_OP_CODES_END + 1,
APM_DUMP_POWER_STATUS,
APM_BIOS_CALL,
APM_SET_SAFETY
};
#define BIOS_APM_GET_POWER_STATUS 0x530a
#endif
PowerStatusView::PowerStatusView(BRect frame, int32 resizingMode, bool inDeskbar)
: BView(frame, kDeskbarItemName, resizingMode,
PowerStatusView::PowerStatusView(PowerStatusDriverInterface* interface,
BRect frame, int32 resizingMode, int batteryId, bool inDeskbar)
:
BView(frame, kDeskbarItemName, resizingMode,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
fDriverInterface(interface),
fBatteryId(batteryId),
fInDeskbar(inDeskbar)
{
fPreferredSize.width = frame.Width();
fPreferredSize.height = frame.Height();
_Init();
if (!inDeskbar) {
// we were obviously added to a standard window - let's add a dragger
frame.OffsetTo(B_ORIGIN);
frame.top = frame.bottom - 7;
frame.left = frame.right - 7;
BDragger* dragger = new BDragger(frame, this,
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
AddChild(dragger);
} else
_Update();
}
@@ -93,14 +69,33 @@ PowerStatusView::PowerStatusView(BMessage* archive)
fShowStatusIcon = value;
if (archive->FindBool("show time", &value) == B_OK)
fShowTime = value;
int32 intValue;
if (archive->FindInt32("battery id", &intValue) == B_OK)
fBatteryId = intValue;
}
PowerStatusView::~PowerStatusView()
{
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
close(fDevice);
#endif
}
status_t
PowerStatusView::Archive(BMessage* archive, bool deep) const
{
status_t status = BView::Archive(archive, deep);
if (status == B_OK)
status = archive->AddBool("show label", fShowLabel);
if (status == B_OK)
status = archive->AddBool("show icon", fShowStatusIcon);
if (status == B_OK)
status = archive->AddBool("show time", fShowTime);
if (status == B_OK)
status = archive->AddInt32("battery id", fBatteryId);
return status;
}
@@ -111,72 +106,10 @@ PowerStatusView::_Init()
fShowTime = false;
fShowStatusIcon = true;
fMessageRunner = NULL;
fPercent = -1;
fOnline = true;
fTimeLeft = 0;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
uint32 version = 0;
status_t status = _kern_generic_syscall(APM_SYSCALLS, B_SYSCALL_INFO,
&version, sizeof(version));
if (status == B_OK) {
battery_info info;
status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO, &info,
sizeof(battery_info));
}
if (status != B_OK) {
fprintf(stderr, "No power interface found.\n");
_Quit();
}
#else
fDevice = open("/dev/misc/apm", O_RDONLY);
if (fDevice < 0) {
fprintf(stderr, "No power interface found.\n");
_Quit();
}
#endif
}
void
PowerStatusView::_Quit()
{
if (fInDeskbar) {
BDeskbar deskbar;
deskbar.RemoveItem(kDeskbarItemName);
} else
be_app->PostMessage(B_QUIT_REQUESTED);
}
PowerStatusView *
PowerStatusView::Instantiate(BMessage* archive)
{
if (!validate_instantiation(archive, "PowerStatusView"))
return NULL;
return new PowerStatusView(archive);
}
status_t
PowerStatusView::Archive(BMessage* archive, bool deep) const
{
status_t status = BView::Archive(archive, deep);
if (status == B_OK)
status = archive->AddString("add_on", kSignature);
if (status == B_OK)
status = archive->AddString("class", "PowerStatusView");
if (status == B_OK)
status = archive->AddBool("show label", fShowLabel);
if (status == B_OK)
status = archive->AddBool("show icon", fShowStatusIcon);
if (status == B_OK)
status = archive->AddBool("show time", fShowTime);
return status;
}
@@ -191,9 +124,6 @@ PowerStatusView::AttachedToWindow()
SetLowColor(ViewColor());
BMessage update(kMsgUpdate);
fMessageRunner = new BMessageRunner(this, &update, kUpdateInterval);
_Update();
}
@@ -201,7 +131,7 @@ PowerStatusView::AttachedToWindow()
void
PowerStatusView::DetachedFromWindow()
{
delete fMessageRunner;
}
@@ -213,35 +143,20 @@ PowerStatusView::MessageReceived(BMessage *message)
_Update();
break;
case kMsgToggleLabel:
fShowLabel = !fShowLabel;
_Update(true);
break;
case kMsgToggleTime:
fShowTime = !fShowTime;
_Update(true);
break;
case kMsgToggleStatusIcon:
fShowStatusIcon = !fShowStatusIcon;
_Update(true);
break;
case B_ABOUT_REQUESTED:
_AboutRequested();
break;
case B_QUIT_REQUESTED:
_Quit();
break;
default:
BView::MessageReceived(message);
}
}
void
PowerStatusView::GetPreferredSize(float *width, float *height)
{
*width = fPreferredSize.width;
*height = fPreferredSize.height;
}
void
PowerStatusView::_DrawBattery(BRect rect)
{
@@ -261,8 +176,7 @@ PowerStatusView::_DrawBattery(BRect rect)
gap = 2;
}
if (fOnline)
SetHighColor(92, 92, 92);
SetHighColor(92, 92, 92);
StrokeRect(rect);
@@ -277,6 +191,8 @@ PowerStatusView::_DrawBattery(BRect rect)
if (percent > 0) {
if (percent < 16)
SetHighColor(180, 0, 0);
else
SetHighColor(20, 180, 0);
rect.InsetBy(gap + 1, gap + 1);
if (gap > 1) {
@@ -358,53 +274,6 @@ PowerStatusView::Draw(BRect updateRect)
}
void
PowerStatusView::MouseDown(BPoint point)
{
BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
menu->SetFont(be_plain_font);
BMenuItem* item;
menu->AddItem(item = new BMenuItem("Show Text Label", new BMessage(kMsgToggleLabel)));
if (fShowLabel)
item->SetMarked(true);
menu->AddItem(item = new BMenuItem("Show Status Icon",
new BMessage(kMsgToggleStatusIcon)));
if (fShowStatusIcon)
item->SetMarked(true);
menu->AddItem(new BMenuItem(!fShowTime ? "Show Time" : "Show Percent",
new BMessage(kMsgToggleTime)));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("About" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED)));
menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED)));
menu->SetTargetForItems(this);
ConvertToScreen(&point);
menu->Go(point, true, false, true);
}
void
PowerStatusView::_AboutRequested()
{
BAlert *alert = new BAlert("about", "PowerStatus\n"
"\twritten by Axel Dörfler\n"
"\tCopyright 2006, Haiku, Inc.\n", "Ok");
BTextView *view = alert->TextView();
BFont font;
view->SetStylable(true);
view->GetFont(&font);
font.SetSize(18);
font.SetFace(B_BOLD_FACE);
view->SetFontAndColor(0, 11, &font);
alert->Go();
}
void
PowerStatusView::_SetLabel(char* buffer, size_t bufferLength)
{
@@ -432,6 +301,7 @@ PowerStatusView::_SetLabel(char* buffer, size_t bufferLength)
}
void
PowerStatusView::_Update(bool force)
{
@@ -439,36 +309,15 @@ PowerStatusView::_Update(bool force)
bool previousTimeLeft = fTimeLeft;
bool wasOnline = fOnline;
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
// TODO: retrieve data from APM/ACPI kernel interface
battery_info info;
status_t status = _kern_generic_syscall(APM_SYSCALLS, APM_GET_BATTERY_INFO, &info,
sizeof(battery_info));
if (status == B_OK) {
fPercent = info.percent;
fTimeLeft = info.time_left;
fOnline = info.online;
}
#else
if (fDevice < 0)
return;
uint16 regs[6] = {0, 0, 0, 0, 0, 0};
regs[0] = BIOS_APM_GET_POWER_STATUS;
regs[1] = 0x1;
if (ioctl(fDevice, APM_BIOS_CALL, regs) == 0) {
fOnline = (regs[1] >> 8) != 0 && (regs[1] >> 8) != 2;
fPercent = regs[2] & 255;
if (fPercent > 100)
fPercent = -1;
fTimeLeft = fPercent >= 0 ? regs[3] : -1;
if (fTimeLeft > 0xffff)
fTimeLeft = -1;
else if (fTimeLeft & 0x8000)
fTimeLeft = (fTimeLeft & 0x7fff) * 60;
}
#endif
_GetBatteryInfo(&fBatteryInfo, fBatteryId);
fPercent = (100 * fBatteryInfo.capacity) / fBatteryInfo.full_capacity;
fTimeLeft = fBatteryInfo.time_left;
if (fBatteryInfo.state & BATTERY_CHARGING)
fOnline = true;
else
fOnline = false;
if (fInDeskbar) {
// make sure the tray icon is large enough
float width = fShowStatusIcon ? kMinIconWidth + 2 : 0;
@@ -496,12 +345,242 @@ PowerStatusView::_Update(bool force)
}
void
PowerStatusView::_GetBatteryInfo(battery_info* batteryInfo, int batteryId)
{
if (batteryId >= 0) {
fDriverInterface->GetBatteryInfo(batteryInfo, batteryId);
}
else for (int i = 0; i < fDriverInterface->GetBatteryCount(); i++) {
battery_info tmpInfo;
fDriverInterface->GetBatteryInfo(&tmpInfo, i);
if (i == 0)
*batteryInfo = tmpInfo;
else {
batteryInfo->state &= tmpInfo.state;
batteryInfo->capacity += tmpInfo.capacity;
batteryInfo->full_capacity += tmpInfo.full_capacity;
batteryInfo->time_left += tmpInfo.time_left;
}
}
}
// #pragma mark -
PowerStatusReplicant::PowerStatusReplicant(BRect frame, int32 resizingMode,
bool inDeskbar)
:
PowerStatusView(NULL, frame, resizingMode, -1, inDeskbar)
{
_Init();
if (!inDeskbar) {
// we were obviously added to a standard window - let's add a dragger
frame.OffsetTo(B_ORIGIN);
frame.top = frame.bottom - 7;
frame.left = frame.right - 7;
BDragger* dragger = new BDragger(frame, this,
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
AddChild(dragger);
} else
_Update();
}
PowerStatusReplicant::PowerStatusReplicant(BMessage* archive)
:
PowerStatusView(archive)
{
_Init();
}
PowerStatusReplicant::~PowerStatusReplicant()
{
if (fExtWindowMessenger)
delete fExtWindowMessenger;
fDriverInterface->StopWatching(this);
fDriverInterface->Disconnect();
delete fDriverInterface;
}
PowerStatusReplicant*
PowerStatusReplicant::Instantiate(BMessage* archive)
{
if (!validate_instantiation(archive, "PowerStatusReplicant"))
return NULL;
return new PowerStatusReplicant(archive);
}
status_t
PowerStatusReplicant::Archive(BMessage* archive, bool deep) const
{
status_t status = PowerStatusView::Archive(archive, deep);
if (status == B_OK)
status = archive->AddString("add_on", kSignature);
if (status == B_OK)
status = archive->AddString("class", "PowerStatusReplicant");
return status;
}
void
PowerStatusReplicant::MessageReceived(BMessage *message)
{
switch (message->what) {
case kMsgToggleLabel:
fShowLabel = !fShowLabel;
_Update(true);
break;
case kMsgToggleTime:
fShowTime = !fShowTime;
_Update(true);
break;
case kMsgToggleStatusIcon:
fShowStatusIcon = !fShowStatusIcon;
_Update(true);
break;
case kMsgToggleExtInfo:
_OpenExtendedWindow();
break;
case B_ABOUT_REQUESTED:
_AboutRequested();
break;
case B_QUIT_REQUESTED:
_Quit();
break;
default:
PowerStatusView::MessageReceived(message);
}
}
void
PowerStatusReplicant::MouseDown(BPoint point)
{
BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING, false, false);
menu->SetFont(be_plain_font);
BMenuItem* item;
menu->AddItem(item = new BMenuItem("Show Text Label",
new BMessage(kMsgToggleLabel)));
if (fShowLabel)
item->SetMarked(true);
menu->AddItem(item = new BMenuItem("Show Status Icon",
new BMessage(kMsgToggleStatusIcon)));
if (fShowStatusIcon)
item->SetMarked(true);
menu->AddItem(new BMenuItem(!fShowTime ? "Show Time" : "Show Percent",
new BMessage(kMsgToggleTime)));
menu->AddItem(new BMenuItem("Battery Info",
new BMessage(kMsgToggleExtInfo)));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("About" B_UTF8_ELLIPSIS,
new BMessage(B_ABOUT_REQUESTED)));
menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED)));
menu->SetTargetForItems(this);
ConvertToScreen(&point);
menu->Go(point, true, false, true);
}
void
PowerStatusReplicant::_AboutRequested()
{
BAlert *alert = new BAlert("about", "PowerStatus\n"
"written by Axel Dörfler,\n"
"\tClemens Zeidler\n"
"\tCopyright 2006, Haiku, Inc.\n", "Ok");
BTextView *view = alert->TextView();
BFont font;
view->SetStylable(true);
view->GetFont(&font);
font.SetSize(18);
font.SetFace(B_BOLD_FACE);
view->SetFontAndColor(0, 11, &font);
alert->Go();
}
void
PowerStatusReplicant::_Init()
{
fDriverInterface = new ACPIDriverInterface;
if (fDriverInterface->Connect() != B_OK) {
delete fDriverInterface;
fDriverInterface = new APMDriverInterface;
if (fDriverInterface->Connect() != B_OK) {
fprintf(stderr, "No power interface found.\n");
_Quit();
}
}
fExtendedWindow = NULL;
fExtWindowMessenger = NULL;
fDriverInterface->StartWatching(this);
}
void
PowerStatusReplicant::_Quit()
{
if (fInDeskbar) {
BDeskbar deskbar;
deskbar.RemoveItem(kDeskbarItemName);
} else
be_app->PostMessage(B_QUIT_REQUESTED);
}
void
PowerStatusReplicant::_OpenExtendedWindow()
{
if (!fExtendedWindow) {
fExtendedWindow = new ExtendedInfoWindow(fDriverInterface);
fExtWindowMessenger = new BMessenger(NULL, fExtendedWindow);
fExtendedWindow->Show();
return;
}
BMessage msg(B_SET_PROPERTY);
msg.AddSpecifier("Hidden", int32(0));
if (fExtWindowMessenger->SendMessage(&msg) == B_BAD_PORT_ID) {
fExtendedWindow = new ExtendedInfoWindow(fDriverInterface);
fExtWindowMessenger = new BMessenger(NULL, fExtendedWindow);
fExtendedWindow->Show();
}
else
fExtendedWindow->Activate();
}
// #pragma mark -
extern "C" _EXPORT BView *
instantiate_deskbar_item(void)
{
return new PowerStatusView(BRect(0, 0, 15, 15), B_FOLLOW_NONE, true);
return new PowerStatusReplicant(BRect(0, 0, 15, 15), B_FOLLOW_NONE, true);
}
+54 -17
View File
@@ -4,53 +4,90 @@
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Clemens Zeidler, haiku@Clemens-Zeidler.de
*/
#ifndef POWER_STATUS_VIEW_H
#define POWER_STATUS_VIEW_H
#include <View.h>
class BMessageRunner;
#include "DriverInterface.h"
class PowerStatusView : public BView {
public:
PowerStatusView(BRect frame, int32 resizingMode, bool inDeskbar = false);
PowerStatusView(BMessage* archive);
PowerStatusView(PowerStatusDriverInterface* interface,
BRect frame, int32 resizingMode, int batteryId = -1,
bool inDeskbar = false);
virtual ~PowerStatusView();
static PowerStatusView* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage* archive, bool deep = true) const;
virtual void AttachedToWindow();
virtual void DetachedFromWindow();
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint where);
virtual void Draw(BRect updateRect);
virtual void GetPreferredSize(float *width, float *height);
protected:
PowerStatusView(BMessage* archive);
virtual void _Update(bool force = false);
virtual void _GetBatteryInfo(battery_info* info, int batteryId);
private:
void _AboutRequested();
void _Quit();
void _Init();
void _SetLabel(char* buffer, size_t bufferLength);
void _Update(bool force = false);
void _DrawBattery(BRect rect);
PowerStatusDriverInterface* fDriverInterface;
BMessageRunner* fMessageRunner;
bool fInDeskbar;
bool fShowLabel;
bool fShowTime;
bool fShowStatusIcon;
int fBatteryId;
bool fInDeskbar;
battery_info fBatteryInfo;
private:
void _Init();
void _SetLabel(char* buffer, size_t bufferLength);
void _DrawBattery(BRect rect);
int32 fPercent;
time_t fTimeLeft;
bool fOnline;
#ifndef HAIKU_TARGET_PLATFORM_HAIKU
int fDevice;
#endif
BSize fPreferredSize;
};
class PowerStatusReplicant : public PowerStatusView
{
public:
PowerStatusReplicant(BRect frame, int32 resizingMode,
bool inDeskbar = false);
PowerStatusReplicant(BMessage* archive);
virtual ~PowerStatusReplicant();
static PowerStatusReplicant* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage* archive, bool deep = true) const;
virtual void MessageReceived(BMessage* message);
virtual void MouseDown(BPoint where);
private:
void _AboutRequested();
void _Init();
void _Quit();
void _OpenExtendedWindow();
BWindow* fExtendedWindow;
BMessenger* fExtWindowMessenger;
};
#endif // POWER_STATUS_VIEW_H
+1 -1
View File
@@ -21,7 +21,7 @@ PowerStatusWindow::PowerStatusWindow()
topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
AddChild(topView);
topView->AddChild(new PowerStatusView(Bounds(), B_FOLLOW_ALL));
topView->AddChild(new PowerStatusReplicant(Bounds(), B_FOLLOW_ALL));
}