You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeutils/klaptopdaemon/daemondock.cpp

757 lines
24 KiB

/*
* daemondock.cpp
* Copyright (C) 1999 Paul Campbell <paul@taniwha.com>
* Copyright (C) 2006 Flavio Castelli <flavio.castelli@gmail.com>
*
* This file contains the docked widget for the laptop battery monitor
*
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <tqcursor.h>
#include <tqslider.h>
#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <dcopclient.h>
#include <dcopref.h>
#include "kpcmciainfo.h"
#include "daemondock.h"
#include "portable.h"
#include <kiconloader.h>
#include <tdeapplication.h>
#include <kprocess.h>
#include <kstandarddirs.h>
#include <tdeconfig.h>
#include <tdeglobalsettings.h>
#include <tdemessagebox.h>
#include <tqvbox.h>
#include <tqstringlist.h>
#include <tqbitmap.h>
#include <tqpainter.h>
#include <kiconeffect.h>
extern void wake_laptop_daemon();
laptop_dock::laptop_dock( laptop_daemon* parent )
: KSystemTray()
{
setCaption(i18n("KLaptop Daemon"));
TDEGlobal::locale()->insertCatalogue("klaptopdaemon"); // For translation of klaptopdaemon messages
_pcmcia = NULL;
pdaemon = parent;
current_code = -1;
brightness_widget = 0;
instance = new TDEInstance("klaptopdaemon");
// popup menu for right mouse button
rightPopup = contextMenu();
SetupPopup();
}
void
laptop_dock::SetupPopup()
{
rightPopup->clear();
rightPopup->insertTitle(SmallIcon("laptop_battery"), "KLaptop", 999); // otherwise we look like KDED
int has_brightness = laptop_portable::has_brightness();
int can_standby = laptop_portable::has_standby();
int can_suspend = laptop_portable::has_suspend();
int can_hibernate = laptop_portable::has_hibernation();
TQStringList profile_list;
int current_profile;
bool *active_list;
bool has_performance = laptop_portable::get_system_performance(0, current_profile, profile_list, active_list);
TQStringList throttle_list;
int current_throttle;
bool has_throttle = laptop_portable::get_system_throttling(0, current_throttle, throttle_list, active_list);
rightPopup->insertItem(SmallIcon("configure"), i18n("&Configure KLaptop..."), this, TQ_SLOT(invokeSetup()));
if (has_brightness)
rightPopup->insertItem(i18n("Screen Brightness..."), this, TQ_SLOT(invokeBrightness()));
if (has_performance) {
performance_popup = new TQPopupMenu(0, "performance");
performance_popup->setCheckable(1);
rightPopup->insertItem(i18n("Performance Profile..."), performance_popup);
connect( performance_popup, TQ_SIGNAL( activated( int ) ), this, TQ_SLOT( activate_performance( int ) ) );
connect( performance_popup, TQ_SIGNAL( aboutToShow() ), this, TQ_SLOT( fill_performance() ) );
} else {
performance_popup = 0;
}
if (has_throttle) {
throttle_popup = new TQPopupMenu(0, "throttle");
throttle_popup->setCheckable(1);
rightPopup->insertItem(i18n("CPU Throttling..."), throttle_popup);
connect( throttle_popup, TQ_SIGNAL( activated( int ) ), this, TQ_SLOT( activate_throttle( int ) ) );
connect( throttle_popup, TQ_SIGNAL( aboutToShow() ), this, TQ_SLOT( fill_throttle() ) );
} else {
throttle_popup = 0;
}
if (can_standby || can_suspend || can_hibernate) {
rightPopup->insertSeparator();
if (can_standby) rightPopup->insertItem(i18n("Standby..."), this, TQ_SLOT(invokeStandby()));
// if (can_suspend) rightPopup->insertItem(i18n("&Lock && Suspend..."), this, TQ_SLOT(invokeLockSuspend()));
if (can_suspend) rightPopup->insertItem(i18n("&Suspend..."), this, TQ_SLOT(invokeLockSuspend()));
// if (can_hibernate) rightPopup->insertItem(i18n("&Lock && Hibernate..."), this, TQ_SLOT(invokeLockHibernation()));
if (can_hibernate) rightPopup->insertItem(i18n("&Hibernate..."), this, TQ_SLOT(invokeLockHibernation()));
}
rightPopup->insertSeparator();
rightPopup->insertItem(i18n("&Hide Monitor"), this, TQ_SLOT(slotHide()));
rightPopup->insertItem(SmallIcon("system-log-out"), KStdGuiItem::quit().text(), this, TQ_SLOT(slotQuit()));
}
laptop_dock::~laptop_dock()
{
delete instance;
if (brightness_widget)
delete brightness_widget;
if (throttle_popup)
delete throttle_popup;
if (performance_popup)
delete performance_popup;
}
void
laptop_dock::activate_throttle(int ind)
{
pdaemon->SetThrottle(throttle_popup->text(ind));
}
void
laptop_dock::fill_throttle()
{
throttle_popup->clear();
int current;
TQStringList list;
bool *active_list;
bool has_throttle = laptop_portable::get_system_throttling(1, current, list, active_list);
if (!has_throttle && !list.empty())
return;
int n=0;
for (TQValueListIterator<TQString> i = list.begin();i != list.end();i++) {
throttle_popup->insertItem(*i, n);
throttle_popup->setItemEnabled(n, active_list[n]);
n++;
}
throttle_popup->setItemChecked(current, 1);
}
void
laptop_dock::activate_performance(int ind)
{
pdaemon->SetPerformance(performance_popup->text(ind));
}
void
laptop_dock::fill_performance()
{
performance_popup->clear();
int current;
TQStringList list;
bool *active_list;
bool has_performance = laptop_portable::get_system_performance(1, current, list, active_list);
if (!has_performance && !list.empty())
return;
int n=0;
for (TQValueListIterator<TQString> i = list.begin();i != list.end();i++) {
performance_popup->insertItem(*i, n);
performance_popup->setItemEnabled(n, active_list[n]);
n++;
}
performance_popup->setItemChecked(current, 1);
}
void
laptop_dock::invokeBrightnessSlider(int v)
{
v=255-v;
pdaemon->SetBrightness(0, v);
brightness = v;
}
void
laptop_dock::invokeBrightness()
{
brightness = pdaemon->GetBrightness();
if (brightness < 0)
brightness = 255;
if (brightness_widget == 0) {
brightness_widget = new TQVBox(0L, "Brightness", WStyle_Customize | WType_Popup);
brightness_widget->setFrameStyle(TQFrame::PopupPanel);
brightness_widget->setMargin(KDialog::marginHint());
brightness_slider = new TQSlider(0, 255, 16, 255-brightness, TQt::Vertical, brightness_widget, 0);
brightness_slider->setMinimumHeight(40);
brightness_slider->setMinimumWidth(15);
connect(brightness_slider, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(invokeBrightnessSlider(int)));
brightness_widget->resize(brightness_widget->sizeHint());
} else {
brightness_slider->setValue(255-brightness);
}
if (!brightness_widget->isVisible()) {
TQRect desktop = TDEGlobalSettings::desktopGeometry(this);
int sw = desktop.width();
int sh = desktop.height();
int sx = desktop.x();
int sy = desktop.y();
TQPoint pos = TQCursor::pos();
int x = pos.x();
int y = pos.y();
y -= brightness_widget->geometry().height();
int w = brightness_widget->width();
int h = brightness_widget->height();
if (x+w > sw)
x = pos.x()-w;
if (y+h > sh)
y = pos.y()-h;
if (x < sx)
x = pos.x();
if (y < sy)
y = pos.y();
brightness_widget->move(x, y);
brightness_widget->show();
}
}
void laptop_dock::slotGoRoot(int /*id*/) {
#ifdef NOTDEF
TQString tdesu = TDEStandardDirs::findExe("tdesu");
if (!tdesu.isEmpty()) {
int rc = KMessageBox::warningContinueCancel(0,
i18n("You will need to supply a root password "
"to allow KLaptopDaemon to restart "
"itself as the superuser. It may take "
"up to a minute for the new daemon to "
"start up and the old one to close."),
i18n("KLaptopDaemon"), KStdGuiItem::cont(),
"switchToPCMCIAPrompt");
if (rc == KMessageBox::Continue) {
TDEProcess *_rootProcess;
_rootProcess = new TDEProcess;
*_rootProcess << tdesu;
*_rootProcess << "-u";
*_rootProcess << "root";
//*_rootProcess << "--nonewdcop";
*_rootProcess << TDEStandardDirs::findExe("klaptopdaemon");
connect(_rootProcess, TQ_SIGNAL(processExited(TDEProcess*)),
this, TQ_SLOT(rootExited(TDEProcess*)));
_rootProcess->start(TDEProcess::NotifyOnExit);
// We should disable this menu item here now.
}
} else {
KMessageBox::sorry(0, i18n("PCMCIA cannot be enabled since tdesu cannot be found. Please make sure that it is installed correctly."),
i18n("KLaptopDaemon"));
}
#else
KMessageBox::sorry(0, i18n("PCMCIA cannot be enabled just now."),
i18n("KLaptopDaemon"));
#endif
}
void laptop_dock::slotHide() {
int confirm = KMessageBox::questionYesNo(0, i18n("Are you sure you want to hide the battery monitor? Your battery will still be monitored in the background."), TQString(), i18n("Hide Monitor"), i18n("Do Not Hide"), "hideConfirm");
if (confirm != KMessageBox::Yes)
return;
// just tell ourselves to hide the battery
TDEConfig *config = new TDEConfig("kcmlaptoprc");
if (config) {
config->setGroup("BatteryDefault");
config->writeEntry("Enable", false);
config->sync();
delete config;
}
wake_laptop_daemon();
}
void laptop_dock::slotQuit() {
int confirm = KMessageBox::questionYesNo(0, i18n("Are you sure you want to quit the battery monitor?"), TQString(), KStdGuiItem::quit(), KStdGuiItem::cancel(), "quitConfirm");
if (confirm != KMessageBox::Yes)
return;
confirm = KMessageBox::questionYesNo(0, i18n("Do you wish to disable the battery monitor from starting in the future?"), TQString(), i18n("Disable"), i18n("Keep Enabled"), "restartMonitor");
if (confirm == KMessageBox::Yes) {
// just tell ourselves to hide the battery
TDEConfig *config = new TDEConfig("kcmlaptoprc");
if (config) {
config->setGroup("BatteryDefault");
config->writeEntry("Enable", false);
config->sync();
delete config;
}
}
pdaemon->quit();
}
void laptop_dock::rootExited(TDEProcess *p) {
if (p && p->isRunning()) {
p->detach();
}
exit(0);
}
void laptop_dock::slotEjectAction(int id) {
KPCMCIACard *f = NULL;
f = _ejectActions[id];
if (f) f->eject();
}
void laptop_dock::slotSuspendAction(int id) {
KPCMCIACard *f = NULL;
f = _suspendActions[id];
if (f) f->suspend();
}
void laptop_dock::slotResumeAction(int id) {
KPCMCIACard *f = NULL;
f = _resumeActions[id];
if (f) f->resume();
}
void laptop_dock::slotResetAction(int id) {
KPCMCIACard *f = NULL;
f = _resetActions[id];
if (f) f->reset();
}
void laptop_dock::slotInsertAction(int id) {
KPCMCIACard *f = NULL;
f = _insertActions[id];
if (f) f->insert();
}
void laptop_dock::slotDisplayAction(int id) {
KPCMCIAInfo *f = new KPCMCIAInfo(_pcmcia);
f->showTab(_displayActions[id]->num());
}
void laptop_dock::mousePressEvent( TQMouseEvent *event )
{
if(event->button() == TQt::LeftButton) {
TQPopupMenu *popup = new TQPopupMenu(0, "popup");
if (!pdaemon->exists()) {
popup->insertItem(i18n("Power Manager Not Found"));
} else {
TQString tmp;
if (pdaemon->val >= 0) {
if (pdaemon->left >= 0) {
TQString num3;
num3.setNum(pdaemon->left%60);
num3 = num3.rightJustify(2, '0');
tmp = i18n("%1:%2 hours left").arg(pdaemon->left/60).arg(num3);
} else {
// no remaining time available
tmp = i18n("%1% charged").arg(pdaemon->val);
}
} else {
tmp = i18n("No Battery");
}
popup->insertItem(tmp);
popup->setItemEnabled(0, 0);
popup->insertSeparator();
if (pdaemon->powered && pdaemon->val >= 0) {
popup->insertItem(i18n("Charging"));
} else {
popup->insertItem(i18n("Not Charging"));
}
popup->setItemEnabled(1, 0);
}
/**
* CPU Frequency scaling support
* - show the cpu profile and current frequency
*/
if (laptop_portable::has_cpufreq()) {
TQString speed = laptop_portable::cpu_frequency();
if (!speed.isEmpty()) {
popup->insertSeparator();
popup->insertItem(i18n("CPU: %1").arg(speed));
}
}
/**
* ADD the PCMCIA entries here
*/
if (_pcmcia && _pcmcia->haveCardServices()) {
TQString slotname = i18n("Slot %1"); // up here so we only construct it once
int id;
popup->insertSeparator();
_ejectActions.clear();
_resetActions.clear();
_insertActions.clear();
_suspendActions.clear();
_resumeActions.clear();
_displayActions.clear();
id = popup->insertItem(i18n("Card Slots..."), this, TQ_SLOT(slotDisplayAction(int)));
_displayActions.insert(id, _pcmcia->getCard(0));
for (int i = 0; i < _pcmcia->getCardCount(); i++) {
KPCMCIACard *thiscard;
thiscard = _pcmcia->getCard(i);
if (thiscard && (thiscard->present())) {
TQPopupMenu *thisSub = new TQPopupMenu(popup, thiscard->name().latin1());
id = thisSub->insertItem(i18n("Details..."), this, TQ_SLOT(slotDisplayAction(int)));
_displayActions.insert(id, thiscard);
// add the actions
TQPopupMenu *actionsSub = new TQPopupMenu(thisSub, "actions");
id = actionsSub->insertItem(i18n("Eject"), this, TQ_SLOT(slotEjectAction(int)));
actionsSub->setItemEnabled(id, !(thiscard->status() & CARD_STATUS_BUSY));
_ejectActions.insert(id, thiscard);
id = actionsSub->insertItem(i18n("Suspend"), this, TQ_SLOT(slotSuspendAction(int)));
actionsSub->setItemEnabled(id, !(thiscard->status() & (CARD_STATUS_SUSPEND|CARD_STATUS_BUSY)));
_suspendActions.insert(id, thiscard);
id = actionsSub->insertItem(i18n("Resume"), this, TQ_SLOT(slotResumeAction(int)));
actionsSub->setItemEnabled(id, (thiscard->status() & CARD_STATUS_SUSPEND));
_resumeActions.insert(id, thiscard);
id = actionsSub->insertItem(i18n("Reset"), this, TQ_SLOT(slotResetAction(int)));
_resetActions.insert(id, thiscard);
id = actionsSub->insertItem(i18n("Insert"), this, TQ_SLOT(slotInsertAction(int)));
_insertActions.insert(id, thiscard);
actionsSub->setItemEnabled(id, !(thiscard->status() & (CARD_STATUS_READY|CARD_STATUS_SUSPEND)));
thisSub->insertItem(i18n("Actions"), actionsSub);
// add a few bits of information
thisSub->insertSeparator();
thisSub->insertItem(slotname.arg(thiscard->num()+1));
if (thiscard->status() & CARD_STATUS_READY)
thisSub->insertItem(i18n("Ready"));
if (thiscard->status() & CARD_STATUS_BUSY)
thisSub->insertItem(i18n("Busy"));
if (thiscard->status() & CARD_STATUS_SUSPEND)
thisSub->insertItem(i18n("Suspended"));
popup->insertItem(thiscard->name(), thisSub);
}
}
} else if (_pcmcia && geteuid() != 0) {
popup->insertItem(i18n("Enable PCMCIA"));
}
popup->popup(TQCursor::pos());
}
}
void laptop_dock::mouseReleaseEvent( TQMouseEvent *e )
{
if ( !rect().contains( e->pos() ) )
return;
switch ( e->button() ) {
case TQt::LeftButton:
break;
case TQt::MidButton:
// fall through
case TQt::RightButton:
{
TDEPopupMenu *menu = contextMenu();
contextMenuAboutToShow( menu );
menu->popup( e->globalPos() );
}
break;
default:
// nothing
break;
}
}
void laptop_dock::showEvent( TQShowEvent * )
{
}
void laptop_dock::invokeHibernation()
{
laptop_portable::invoke_hibernation();
}
void laptop_dock::invokeLockHibernation()
{
DCOPRef dr("kdesktop", "KScreensaverIface");
DCOPReply reply=dr.call("lock");
laptop_portable::invoke_hibernation();
}
void laptop_dock::invokeStandby()
{
laptop_portable::invoke_standby();
}
void laptop_dock::invokeSuspend()
{
laptop_portable::invoke_suspend();
}
void laptop_dock::invokeLockSuspend()
{
DCOPClient* client = kapp->dcopClient();
if (client)
client->send("kdesktop", "KScreensaverIface", "lock()", TQString(""));
laptop_portable::invoke_suspend();
}
void laptop_dock::invokeSetup()
{
TDEProcess proc;
proc << TDEStandardDirs::findExe("tdecmshell");
proc << "laptop";
proc.start(TDEProcess::DontCare);
proc.detach();
}
void
laptop_dock::reload_icon()
{
// we will try to deduce the pixmap (or gif) name now. it will
// vary depending on the dock and power
TQString pixmap_name;
if (!pdaemon->exists())
pixmap_name = pdaemon->noBatteryIcon();
else if (!pdaemon->powered)
pixmap_name = pdaemon->noChargeIcon();
else
pixmap_name = pdaemon->chargeIcon();
pm = loadIcon( pixmap_name, instance );
}
void laptop_dock::displayPixmap()
{
int new_code;
if (!pdaemon->exists())
new_code = 1;
else if (!pdaemon->powered)
new_code = 2;
else
new_code = 3;
if (current_code != new_code) {
current_code = new_code;
reload_icon();
}
// at this point, we have the file to display. so display it
TQImage image = pm.convertToImage();
const TQBitmap *bmmask = pm.mask();
TQImage mask;
if (bmmask)
mask = bmmask->convertToImage();
int w = image.width();
int h = image.height();
int count = 0;
TQRgb rgb;
int x, y;
for (x = 0; x < w; x++)
for (y = 0; y < h; y++)
if (!bmmask || mask.pixelIndex(x, y) != 0){
rgb = image.pixel(x, y);
if (tqRed(rgb) == 0xff &&
tqGreen(rgb) == 0xff &&
tqBlue(rgb) == 0xff)
count++;
}
int c = (count*pdaemon->val)/100;
if (pdaemon->val == 100) {
c = count;
} else
if (pdaemon->val != 100 && c == count)
c = count-1;
if (c) {
uint ui;
TQRgb blue = tqRgb(0x00,0x00,0xff);
if (image.depth() <= 8) {
ui = image.numColors(); // this fix thanks to Sven Krumpke
image.setNumColors(ui+1);
image.setColor(ui, blue);
} else {
ui = 0xff000000|blue;
}
for (y = h-1; y >= 0; y--)
for (x = 0; x < w; x++)
if (!bmmask || mask.pixelIndex(x, y) != 0){
rgb = image.pixel(x, y);
if (tqRed(rgb) == 0xff &&
tqGreen(rgb) == 0xff &&
tqBlue(rgb) == 0xff) {
image.setPixel(x, y, ui);
c--;
if (c <= 0)
goto quit;
}
}
}
quit:
TQString tmp;
TQString levelString;
if (!pdaemon->exists()) {
tmp = i18n("Laptop power management not available");
levelString = i18n("N/A");
} else
if (pdaemon->powered) {
if (pdaemon->val == 100) {
tmp = i18n("Plugged in - fully charged");;
levelString = "100%";
} else if (pdaemon->val >= 0) {
levelString.sprintf ("%i%%", pdaemon->val);
if (pdaemon->left >= 0) {
TQString num3;
num3.setNum(pdaemon->left%60);
num3 = num3.rightJustify(2, '0');
tmp = i18n("Plugged in - %1% charged (%2:%3 hours left)")
.arg(pdaemon->val).arg(pdaemon->left/60).arg(num3);
} else {
// no remaining time available
tmp = i18n("Plugged in - %1% charged").arg(pdaemon->val);
}
} else {
tmp = i18n("Plugged in - no battery");
levelString = i18n("N/A");
}
} else {
if (pdaemon->val >= 0) {
levelString.sprintf ("%i%%", pdaemon->val);
if (pdaemon->left >= 0) {
TQString num3;
num3.setNum(pdaemon->left%60);
num3 = num3.rightJustify(2, '0');
tmp = i18n("Running on batteries - %1% charged (%2:%3 hours left)")
.arg(pdaemon->val).arg(pdaemon->left/60).arg(num3);
} else {
tmp = i18n("Running on batteries - %1% charged").arg(pdaemon->val);
}
} else {
// running without any power source...
// happens eg. due to ACPI not being able to handle battery hot-plugin
tmp = i18n("No power source found");
levelString = i18n("N/A");
}
}
// prepare icon for systemtray
TDEConfig* config = new TDEConfig("kcmlaptoprc");
bool showlevel = false;
if (config)
{
config->setGroup("BatteryDefault");
showlevel= config->readBoolEntry("ShowLevel", false);
delete config;
}
if (showlevel)
{
// lot of code taken from kmail kmsystemtray class
int oldPixmapWidth = image.size().width();
int oldPixmapHeight = image.size().height();
TQFont percentageFont = TDEGlobalSettings::generalFont();
percentageFont.setBold(true);
// decrease the size of the font for the number of unread messages if the
// number doesn't fit into the available space
float percentageFontSize = percentageFont.pointSizeFloat();
TQFontMetrics qfm( percentageFont );
int width = qfm.width( levelString );
if( width > oldPixmapWidth )
{
percentageFontSize *= float( oldPixmapWidth ) / float( width );
percentageFont.setPointSizeFloat( percentageFontSize );
}
// Create an image which represents the number of unread messages
// and which has a transparent background.
// Unfortunately this required the following twisted code because for some
// reason text that is drawn on a transparent pixmap is invisible
// (apparently the alpha channel isn't changed when the text is drawn).
// Therefore I have to draw the text on a solid background and then remove
// the background by making it transparent with TQPixmap::setMask. This
// involves the slow createHeuristicMask() function (from the API docs:
// "This function is slow because it involves transformation to a TQImage,
// non-trivial computations and a transformation back to a TQBitmap."). Then
// I have to convert the resulting TQPixmap to a TQImage in order to overlay
// the light KMail icon with the number (because TDEIconEffect::overlay only
// works with TQImage). Finally the resulting TQImage has to be converted
// back to a TQPixmap.
// That's a lot of work for overlaying the KMail icon with the number of
// unread messages, but every other approach I tried failed miserably.
// IK, 2003-09-22
TQPixmap percentagePixmap( oldPixmapWidth, oldPixmapHeight );
percentagePixmap.fill( TQt::white );
TQPainter p( &percentagePixmap );
p.setFont( percentageFont );
p.setPen( TQt::black );
p.drawText( percentagePixmap.rect(), TQt::AlignCenter, levelString );
percentagePixmap.setMask( percentagePixmap.createHeuristicMask() );
TQImage percentageImage = percentagePixmap.convertToImage();
// Overlay the light KMail icon with the number image
TQImage iconWithPercentageImage = image.copy();
TDEIconEffect::overlay( iconWithPercentageImage, percentageImage );
TQPixmap iconWithPercentage;
iconWithPercentage.convertFromImage( iconWithPercentageImage );
setPixmap( iconWithPercentage );
}
else
{
TQPixmap q;
q.convertFromImage(image);
if (bmmask)
q.setMask(*bmmask);
setPixmap(q);
}
adjustSize();
TQToolTip::add(this, tmp);
}
#include "daemondock.moc"