summaryrefslogtreecommitdiffstats
path: root/kmilo/thinkpad
diff options
context:
space:
mode:
Diffstat (limited to 'kmilo/thinkpad')
-rw-r--r--kmilo/thinkpad/Makefile.am36
-rw-r--r--kmilo/thinkpad/README61
-rw-r--r--kmilo/thinkpad/kcmthinkpad/Makefile.am15
-rw-r--r--kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui307
-rw-r--r--kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui.h36
-rw-r--r--kmilo/thinkpad/kcmthinkpad/main.cpp189
-rw-r--r--kmilo/thinkpad/kcmthinkpad/main.h49
-rw-r--r--kmilo/thinkpad/kcmthinkpad/thinkpad.desktop145
-rw-r--r--kmilo/thinkpad/kmilo_thinkpad.desktop101
-rw-r--r--kmilo/thinkpad/thinkpad.cpp556
-rw-r--r--kmilo/thinkpad/thinkpad.h208
11 files changed, 1703 insertions, 0 deletions
diff --git a/kmilo/thinkpad/Makefile.am b/kmilo/thinkpad/Makefile.am
new file mode 100644
index 0000000..e82c26b
--- /dev/null
+++ b/kmilo/thinkpad/Makefile.am
@@ -0,0 +1,36 @@
+# This file is part of the KDE project
+# Copyright (C) 2003 George Staikos <staikos@kde.org>
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+
+# This library 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public License
+# along with this library; see the file COPYING.LIB. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+SUBDIRS = . kcmthinkpad
+
+INCLUDES=-I$(srcdir)/../kmilod $(all_includes)
+
+kde_module_LTLIBRARIES = kmilo_thinkpad.la
+
+kmilo_thinkpad_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+kmilo_thinkpad_la_LIBADD = ../kmilod/libkmilo.la $(LIB_KIO)
+kmilo_thinkpad_la_SOURCES = thinkpad.cpp
+METASOURCES = AUTO
+
+noinst_HEADERS = thinkpad.h
+
+services_DATA = kmilo_thinkpad.desktop
+servicesdir = $(kde_servicesdir)/kmilo
+
+messages:
+ $(XGETTEXT) $(kmilo_thinkpad_la_SOURCES) -o $(podir)/kmilo_thinkpad.pot
diff --git a/kmilo/thinkpad/README b/kmilo/thinkpad/README
new file mode 100644
index 0000000..56b5da0
--- /dev/null
+++ b/kmilo/thinkpad/README
@@ -0,0 +1,61 @@
+Thinkpad Buttons KMilo Plugin
+
+Jonathan Riddell jr@jriddell.org, January 2004
+
+A port of tpb ( http://www.nongnu.org/tpb/ ) to KMilo.
+
+KMilo is a service for kded, the KDE daemon. KMilo is new to KDE 3.2.
+It allows plugins which interact with the special buttons found on
+some keyboards and laptops.
+
+This KMilo plugin reads the nvram used in IBM Thinkpads. You need the
+Linux nvram module ('insmod nvram') and to create a device node
+('mknod /dev/nvram c 10 144').
+
+Thinkpad R30/R31 models do not have a hardware volume control and so
+require software volume control. Other models need software volume
+control only if you want a volume change step different from the
+builtin value (14). This required write access to nvram ('chmod 666
+/dev/nvram') and could potentially damage the machine.
+
+A KControl Centre module is included to configure the values including
+whether this service is run or not (by default it is not).
+
+INSTALL:
+
+Download kdeutils source for kde 3.2 or newer. Then compile as
+usual starting from the kdeutils directory:
+
+ make -f Makefile.cvs
+ ./configure
+ cd kmilo
+ make
+ sudo make install
+
+Restarting kded is probably needed:
+
+ kdekillall kded
+ kded
+
+HISTORY:
+
+05 January 2004, Initial release, most things working
+
+21 January 2004, Bug fix, stop it crashing if starting without kmix
+ runningdisplay rounded min and max volume levels, pda icon for
+ KControl module
+
+24 January 2004, Stopped it start kmix on kded startup even when set not to run
+
+28 January 2004, Added to KDE CVS
+
+TODO:
+
+ - Need a better icon for the KControl module
+ - Test on machines other than my R31, which only has volume,
+ brightness buttons, light and 'Thinkpad' buttons
+ - Add options for the 'Thinkpad' and other action buttons to do something (e.g. bring up Konqueror)
+ For this sort of thing we really want integration with KHotKeys but I'm not sure how
+
+
+
diff --git a/kmilo/thinkpad/kcmthinkpad/Makefile.am b/kmilo/thinkpad/kcmthinkpad/Makefile.am
new file mode 100644
index 0000000..4e70c40
--- /dev/null
+++ b/kmilo/thinkpad/kcmthinkpad/Makefile.am
@@ -0,0 +1,15 @@
+kde_module_LTLIBRARIES = kcm_thinkpad.la
+
+kcm_thinkpad_la_SOURCES = kcmthinkpad_general.ui main.cpp
+
+kcm_thinkpad_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+kcm_thinkpad_la_LIBADD = $(LIB_KIO)
+
+INCLUDES= $(all_includes) -DKDE_BINDIR="\"$(bindir)\""
+
+kcm_thinkpad_la_METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kcmthinkpad.pot
+
+xdg_apps_DATA = thinkpad.desktop
diff --git a/kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui b/kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui
new file mode 100644
index 0000000..771b7bf
--- /dev/null
+++ b/kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui
@@ -0,0 +1,307 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KCMThinkpadGeneral</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KCMThinkpadGeneral</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>559</width>
+ <height>548</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>KVaio: General Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>tlOff</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>Could not read /dev/nvram. If you have an IBM Thinkpad load the nvram Linux module &lt;em&gt;insmod nvram&lt;/em&gt; and create the node &lt;em&gt;mknod /dev/nvram c 10 144&lt;/em&gt; then make the device readable &lt;em&gt;chmod 664 /dev/nvram&lt;/em&gt; or writable &lt;em&gt;chmod 666 /dev/nvram&lt;/em&gt;.&lt;p&gt; nvram must be writable for software volume control required for R30/R31 models and for using a custom volume change step.</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0">
+ <property name="name">
+ <cstring>bgGeneral</cstring>
+ </property>
+ <property name="title">
+ <string>Thinkpad Button Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>mCbRun</cstring>
+ </property>
+ <property name="text">
+ <string>Run Thinkpad Buttons KMilo plugin</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>mCbSoftwareVolume</cstring>
+ </property>
+ <property name="text">
+ <string>Change volume in software (required by R30/R31)</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout27</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel2_5</cstring>
+ </property>
+ <property name="text">
+ <string>Command for Mail button:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel2_6</cstring>
+ </property>
+ <property name="text">
+ <string>Command for FN-Zoom button:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="2" column="1">
+ <property name="name">
+ <cstring>commandExecHome</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>Command for Search button:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="1">
+ <property name="name">
+ <cstring>commandExec</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>volumeStepLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>Volume step (out of 100):</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="5" column="1">
+ <property name="name">
+ <cstring>commandExecZoom</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Command for Home button:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>mSpinboxVolumeStep</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maxValue">
+ <number>30</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="3" column="1">
+ <property name="name">
+ <cstring>commandExecSearch</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Command for Thinkpad button:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="4" column="1">
+ <property name="name">
+ <cstring>commandExecMail</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>mCbRun</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>mCbSoftwareVolume</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>mSpinboxVolumeStep</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>commandExec</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>commandExecHome</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>commandExecMail</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>commandExecSearch</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+ <connection>
+ <sender>commandExecZoom</sender>
+ <signal>textChanged(const QString&amp;)</signal>
+ <receiver>KCMThinkpadGeneral</receiver>
+ <slot>slotChanged()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>mCbRun</tabstop>
+ <tabstop>mCbSoftwareVolume</tabstop>
+ <tabstop>mSpinboxVolumeStep</tabstop>
+ <tabstop>commandExec</tabstop>
+ <tabstop>commandExecHome</tabstop>
+ <tabstop>commandExecSearch</tabstop>
+ <tabstop>commandExecMail</tabstop>
+</tabstops>
+<includes>
+ <include location="local" impldecl="in implementation">kcmthinkpad_general.ui.h</include>
+</includes>
+<signals>
+ <signal>changed();</signal>
+</signals>
+<slots>
+ <slot>slotChanged()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui.h b/kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui.h
new file mode 100644
index 0000000..6ccc675
--- /dev/null
+++ b/kmilo/thinkpad/kcmthinkpad/kcmthinkpad_general.ui.h
@@ -0,0 +1,36 @@
+/*
+ * kcmthinkpad_general.uih
+ *
+ * Copyright (C) 2004 Jonathan Riddell <jr@jriddell.org>
+ *
+ * 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.
+ *
+ */
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+#include <kdialog.h>
+
+void KCMThinkpadGeneral::slotChanged() {
+ emit(changed());
+}
+
+
+
diff --git a/kmilo/thinkpad/kcmthinkpad/main.cpp b/kmilo/thinkpad/kcmthinkpad/main.cpp
new file mode 100644
index 0000000..1b8b4bd
--- /dev/null
+++ b/kmilo/thinkpad/kcmthinkpad/main.cpp
@@ -0,0 +1,189 @@
+/*
+ * main.cpp
+ *
+ * Copyright (C) 2004 Jonathan Riddell <jr@jriddell.org>
+ *
+ * Based on kcm_kvaio
+ * Copyright (C) 2003 Mirko Boehm (mirko@kde.org)
+ *
+ * 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 <qlabel.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qspinbox.h>
+#include <qfile.h>
+#include <qbuttongroup.h>
+
+#include <dcopclient.h>
+#include <kgenericfactory.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <kurlrequester.h>
+#include <kcmodule.h>
+
+#ifdef Q_OS_FREEBSD
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+#include "kcmthinkpad_general.h"
+
+#include <dcopclient.h>
+
+#include "main.h"
+#include "main.moc"
+
+typedef KGenericFactory<KCMThinkpadModule, QWidget> KCMThinkpadModuleFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_thinkpad, KCMThinkpadModuleFactory("kcmthinkpad"))
+
+#define CONFIG_FILE "kmilodrc"
+
+KCMThinkpadModule::KCMThinkpadModule(QWidget* parent, const char* name, const QStringList&)
+ : KCModule(KCMThinkpadModuleFactory::instance(), parent, name) {
+ KAboutData* about =
+ new KAboutData(I18N_NOOP("kcmthinkpad"),
+ I18N_NOOP("KDE Control Module for IBM Thinkpad "
+ "Laptop Hardware"),
+ 0, 0, KAboutData::License_GPL,
+ "(c) 2004 Jonathan Riddell");
+
+ about->addAuthor("Jonathan Riddell",
+ I18N_NOOP("Original author"),
+ "jr@jriddell.org");
+ setAboutData( about );
+
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ m_KCMThinkpadGeneral = new KCMThinkpadGeneral(this);
+ layout->addWidget( m_KCMThinkpadGeneral );
+ layout->addStretch();
+
+ load();
+
+ //try and open /dev/nvram
+ m_nvramReadable = false;
+ m_nvramWriteable = false;
+
+#ifdef Q_OS_FREEBSD
+ // Look if the sysctl tree of acpi_ibm is in place
+ u_int n = 0;
+ size_t len = sizeof(n);
+ if (m_nvramReadable = ( sysctlbyname("dev.acpi_ibm.0.volume", &n, &len, NULL, 0) != -1 ))
+ m_nvramWriteable = ( sysctlbyname("dev.acpi_ibm.0.volume", NULL, NULL, &n, len) != -1 );
+
+ if (!m_nvramReadable) {
+ setButtons(buttons() & ~Default);
+ m_KCMThinkpadGeneral->bgGeneral->setEnabled(false);
+ m_KCMThinkpadGeneral->tlOff->setText(i18n("In order to use the Thinkpad Buttons KMilo Plugin, "
+ "you have to load the acpi_ibm(4) driver."));
+ } else if (!m_nvramWriteable) {
+ m_KCMThinkpadGeneral->tlOff->setText(i18n("Could not write to dev.acpi_ibm.0.volume. "
+ "Using software volume, required for "
+ "R30/R31 models, or using a custom volume "
+ "change step is disabled."));
+#else
+ QFile nvramFile(m_nvramFile);
+ if ( nvramFile.open(IO_ReadOnly) ) {
+ m_nvramReadable = true;
+ nvramFile.close();
+ }
+ if ( nvramFile.open(IO_WriteOnly) ) {
+ m_nvramWriteable = true;
+ nvramFile.close();
+ }
+
+ if (!m_nvramReadable) {
+ setButtons(buttons() & ~Default);
+ m_KCMThinkpadGeneral->bgGeneral->setEnabled(false);
+ } else if (!m_nvramWriteable) {
+ m_KCMThinkpadGeneral->tlOff->setText(i18n("Could not write to %1. "
+ "To use the software volume, required for "
+ "R30/R31 models and to use a custom volume "
+ "change step, set the nvram device to world "
+ "writeable: <em>chmod 666 "
+ "/dev/nvram</em>").arg(m_nvramFile));
+#endif
+ } else {
+ m_KCMThinkpadGeneral->tlOff->setText(i18n("Thinkpad Buttons KMilo Plugin Ready For Configuration"));
+ }
+
+ connect( m_KCMThinkpadGeneral, SIGNAL(changed()), SLOT(changed()));
+
+}
+
+void KCMThinkpadModule::save() {
+ if (!m_nvramReadable) {
+ return;
+ }
+ DCOPClient client;
+
+ KConfig config(CONFIG_FILE);
+ config.setGroup("thinkpad");
+
+ config.writeEntry("run", m_KCMThinkpadGeneral->mCbRun->isChecked());
+ config.writeEntry("softwareVolume", m_KCMThinkpadGeneral->mCbSoftwareVolume->isChecked());
+ config.writeEntry("volumeStep", m_KCMThinkpadGeneral->mSpinboxVolumeStep->value());
+ config.writeEntry("buttonThinkpad", m_KCMThinkpadGeneral->commandExec->url());
+ config.writeEntry("buttonHome", m_KCMThinkpadGeneral->commandExecHome->url());
+ config.writeEntry("buttonSearch", m_KCMThinkpadGeneral->commandExecSearch->url());
+ config.writeEntry("buttonMail", m_KCMThinkpadGeneral->commandExecMail->url());
+ config.writeEntry("buttonZoom", m_KCMThinkpadGeneral->commandExecZoom->url());
+ config.sync();
+
+ if (client.attach()) {
+ QByteArray data, replyData;
+ QCString replyType;
+
+ if (!client.call("kded", "kmilod", "reconfigure()", data, replyType, replyData)) {
+ kdDebug() << "KCMThinkpad::showTextMsg: "
+ << "there was an error using DCOP on kmilod::reconfigure()." << endl;
+ }
+ } else {
+ kdDebug() << "KCMThinkpadModule: cannot attach to DCOP server, "
+ << "no automatic config update." << endl;
+ }
+}
+
+void KCMThinkpadModule::load() {
+ load( false );
+}
+
+void KCMThinkpadModule::load(bool useDefaults) {
+ KConfig config(CONFIG_FILE);
+
+ config.setReadDefaults( useDefaults );
+
+ config.setGroup("thinkpad");
+
+ m_KCMThinkpadGeneral->mCbRun->setChecked(config.readBoolEntry("run", false));
+ m_KCMThinkpadGeneral->mCbSoftwareVolume->setChecked(config.readBoolEntry("softwareVolume", true));
+ m_KCMThinkpadGeneral->mSpinboxVolumeStep->setValue(config.readNumEntry("volumeStep", 14));
+ m_KCMThinkpadGeneral->commandExec->setURL(config.readEntry("buttonThinkpad", KDE_BINDIR "/konsole"));
+ m_KCMThinkpadGeneral->commandExecHome->setURL(config.readEntry("buttonHome", KDE_BINDIR "/konqueror"));
+ m_KCMThinkpadGeneral->commandExecSearch->setURL(config.readEntry("buttonSearch", KDE_BINDIR "/kfind"));
+ m_KCMThinkpadGeneral->commandExecMail->setURL(config.readEntry("buttonMail", KDE_BINDIR "/kmail"));
+ m_KCMThinkpadGeneral->commandExecZoom->setURL(config.readEntry("buttonZoom", KDE_BINDIR "/ksnapshot"));
+ m_nvramFile = config.readEntry("nvram", "/dev/nvram");
+
+ emit changed( useDefaults );
+}
+
+void KCMThinkpadModule::defaults() {
+ load( true );
+}
+
diff --git a/kmilo/thinkpad/kcmthinkpad/main.h b/kmilo/thinkpad/kcmthinkpad/main.h
new file mode 100644
index 0000000..53534ed
--- /dev/null
+++ b/kmilo/thinkpad/kcmthinkpad/main.h
@@ -0,0 +1,49 @@
+/*
+ * main.h
+ *
+ * Copyright (C) 2004 Jonathan Riddell <jr@jriddell.org>
+ *
+ * Based on kcm_kvaio
+ * Copyright (C) 2003 Mirko Boehm (mirko@kde.org)
+ *
+ * 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.
+ *
+ */
+
+#ifndef KCMTHINKPAD_MAIN_H
+#define KCMTHINKPAD_MAIN_H
+
+#include <kcmodule.h>
+
+class KCMThinkPadGeneral;
+
+class KCMThinkpadModule : public KCModule {
+ Q_OBJECT
+
+ public:
+ KCMThinkpadModule(QWidget* parent, const char* name, const QStringList&);
+
+ void save();
+ void load();
+ void load(bool useDefaults);
+ void defaults();
+ private:
+ KCMThinkpadGeneral* m_KCMThinkpadGeneral;
+ QString m_nvramFile;
+ bool m_nvramReadable;
+ bool m_nvramWriteable;
+};
+
+#endif
diff --git a/kmilo/thinkpad/kcmthinkpad/thinkpad.desktop b/kmilo/thinkpad/kcmthinkpad/thinkpad.desktop
new file mode 100644
index 0000000..720a69f
--- /dev/null
+++ b/kmilo/thinkpad/kcmthinkpad/thinkpad.desktop
@@ -0,0 +1,145 @@
+[Desktop Entry]
+Type=Application
+Exec=kcmshell thinkpad
+Icon=laptop
+DocPath=kcontrol/thinkpad/index.html
+
+X-KDE-Library=thinkpad
+X-KDE-ParentApp=kcontrol
+
+Name=IBM Thinkpad Laptop
+Name[ar]=حاسوب IBM Thinkpad المحمول
+Name[bg]=Лаптоп IBM Thinkpad
+Name[br]=Hezoug IBM Thinkpad
+Name[bs]=IBM Thinkpad laptop
+Name[ca]=Portàtil IBM Thinkpad
+Name[cy]=Gliniadur IBM Thinkpad
+Name[da]=IBM Thinkpad bærbar
+Name[de]=IBM Thinkpad Notebook
+Name[el]=Φορητός υπολογιστής IBM Thinkpad
+Name[es]=Portátil IBM Thinkpad
+Name[et]=IBM Thinkpadi sülearvuti
+Name[eu]=IBM Thinkpad Magalekoa
+Name[fa]=IBM Thinkpad رایانۀ کیفی
+Name[fi]=IBM Thinkpad -kannettava
+Name[fr]=Portable Thinkpad d'IBM
+Name[ga]=Ríomhaire Glúine IBM Thinkpad
+Name[he]=מחשב ברכיים מסוג IBM Thinkpad
+Name[hu]=IBM Thinkpad noteszgép
+Name[is]=IBM ferðavél
+Name[it]=Portatile IBM Thinkpad
+Name[ja]=IBM シンクパッド ラップトップ
+Name[kk]=IBM Thinkpad ноутбугі
+Name[km]=កុំព្យូទ័រ​យួរដៃ IBM Thinkpad
+Name[mk]=Лаптоп IBM Thinkpad
+Name[nb]=IBM Thinkpad Bærbar PC
+Name[nds]=IBM Thinkpad-Klappreekner
+Name[ne]=IBM थिङ्कप्याड ल्यापटप
+Name[nn]=IBM Thinkpad-bærbar
+Name[pa]=IBM Thinkpad ਲੈਪਟਾਪ
+Name[pl]=Laptop IBM Thinkpad
+Name[pt]=Portátil IBM Thinkpad
+Name[pt_BR]=Laptop IBM Thinkpad
+Name[ro]=Laptop IBM Thinkpad
+Name[ru]=Ноутбук IBM Thinkpad
+Name[sk]=IBM Thinkpad
+Name[sl]=Prenosnik IBM Thinkpad
+Name[sr]=IBM-ов Thinkpad лаптоп
+Name[sr@Latn]=IBM-ov Thinkpad laptop
+Name[sv]=IBM Thinkpad bärbar dator
+Name[ta]=ஐபிஎம் திங்க்பாட் மடிக்கணினி
+Name[tr]=IBM Thinkpad Dizüstü
+Name[uk]=Лептоп IBM Thinkpad
+Name[uz]=IBM Thinkpad laptopi
+Name[uz@cyrillic]=IBM Thinkpad лаптопи
+Name[zh_CN]=ThinkPad 便携电脑
+Name[zh_TW]=IBM Thinkpad 筆記型電腦
+Comment=Configure the KDE Interface to the IBM Thinkpad Special Controls
+Comment[ar]=إعداد واجهة كدى لمُتَحكّمات IBM Thinkpad الخاصة
+Comment[bg]=Настройване на IBM Thinkpad
+Comment[bs]=Podesite KDE interfejs za IBM Thinkpad posebne kontrole
+Comment[ca]=Configura la interfície entre KDE i els controls especials de IBM Thinkpad
+Comment[cs]=Nastavení KDE rozhraní ovládání notebooků IBM Thinkpad
+Comment[cy]=Ffurfweddu'r Rhyngwyneb KDE i'r Rheolau Arbennig IBM Thinkpad
+Comment[da]=Indstil KDE's grænseflade til IBM Thinkpads specielle kontroller
+Comment[de]=KDE Schnittstelle zu den Sonderfunktionen von IBM Thinkpads einrichten
+Comment[el]=Ρυθμίστε το περιβάλλον χρήσης του KDE για τα ειδικά χειριστήρια του IBM Thinkpad
+Comment[es]=Configurar la interfaz de KDE para los controles especiales del IBM Thinkpad
+Comment[et]=KDE liides IBM Thinkpadi eriklahvide seadistamiseks
+Comment[eu]=IBM Thinkpad-en Aginte Berezientzako KDE Interfazea Konfiguratu
+Comment[fa]=پیکربندی واسط KDEدر کلیدهای مهار ویژۀ IBM Thinkpad
+Comment[fi]=Aseta KDE:n liityntää IBM Thinkpadin ohjelmoitavalle keskeytysajurille
+Comment[fr]=Configuration de l'interface KDE pour le paramètrage des Thinkpad d'IBM
+Comment[ga]=Cumraigh comhéadan KDE do Rialtáin Speisialta IBM Thinkpad
+Comment[he]=הגדר את המנשק של KDE להתאים למקשים המיוחדים של IBM Thinkpad
+Comment[hu]=Az IBM Thinkpad noteszgépek speciális kezelőelemeinek beállítása
+Comment[is]=Stilla viðmót KDE á IBM Thinkpad stýringuna
+Comment[it]=Configura l'interfaccia KDE ai controlli speciali dei Thinkpad IBM
+Comment[ja]=IBM シンクパッド特殊コントロールの KDE インターフェースを設定
+Comment[ka]= KDE ინტერფეისის IBM Thinkpad-ის სპეციალური კონტროლებისთვის კონფიგურაცია
+Comment[kk]=IBM Thinkpad арнаулы тетіктерінің KDE интерфейсін баптау
+Comment[km]=កំណត់​រចនា​សម្ព័ន្ធ​ចំណុច​ប្រទាក់ KDE ទៅ​ការត្រួតពិនិត្យ IBM Thinkpad ពិសេស
+Comment[lt]=IBM Thinkpad ypatingiems valdymo moduliams KDE sąsaja
+Comment[mk]=Го конфигурира интерфејсот на KDE за спец. контроли на IBM Thinkpad
+Comment[nb]=Sett opp KDE-grensesnitt til IBM Thinkpad spesial kontroller
+Comment[nds]=KDE-Koppelsteedinstellen för de IBM Thinkpad-Sünnerfunkschonenkuntrull
+Comment[ne]=IBM थिङ्कप्याड विशेष नियन्त्रणका लागि KDE इन्टरफेस कन्फिगर गर्नुहोस्
+Comment[nl]=Voor het instellen van KDE's communicatie met de IBM Thinkpad Special Controls
+Comment[nn]=Set opp KDE-grensesnittet til spesialfunksjonar på IBM Thinkpad
+Comment[pa]=IBM ਥਿੰਕਪੈਂਡ ਕੰਟਰੋਲਾਂ ਲਈ KDE ਇੰਟਰਫੇਸ ਸੰਰਚਨਾ
+Comment[pl]=Konfiguracja specjalnych funkcji IBM Thinkpad
+Comment[pt]=Configurar a Interface para o KDE dos Comandos Especiais do IBM Thinkpad
+Comment[pt_BR]=Configura a Interface do KDE para os Controles Especiais do IBM Thinkpad
+Comment[ro]=Configurează interfaţa KDE către laptop-uri IBM Thinkpad
+Comment[ru]=Настройка интерфейса KDE для специальных клавиш ноутбука IBM Thinkpad
+Comment[sk]=Nastavenie rozhrania KDE k špeciálnym ovládacím prvkom notebooku IBM Thinkpad
+Comment[sl]=Nastavite vmesnik KDE za posebne kontrole IBM Thinkpada
+Comment[sr]=Подесите KDE-ов интерфејс за посебне контроле IBM-ових Thinkpad-ова
+Comment[sr@Latn]=Podesite KDE-ov interfejs za posebne kontrole IBM-ovih Thinkpad-ova
+Comment[sv]=Anpassa KDE:s gränssnitt till IBM Thinkpads specialstyrning
+Comment[ta]=ஐபிஎம் திங்க்பேட் விசேஷ கட்டுப்பாட்டிற்கு கேடிஇ இடைமுகத்தை வடிவமை
+Comment[tr]=KDE Arayüzünü Sony IBM Thinkpad Özel Denetimlerine Ayarla
+Comment[uk]=Налаштування інтерфейсу KDE до спеціальних функцій IBM Thinkpad
+Comment[zh_CN]=配置 KDE 界面使用 ThinkPad 特殊控制
+Comment[zh_TW]=設定 IBM Thinkpad 特殊控制的 KDE 介面
+Keywords=IBM, Thinkpad, brightness, mute, Jog Dial
+Keywords[bs]=IBM, Thinkpad, brightness, mute, Jog Dial, svjetlost
+Keywords[ca]=IBM, Thinkpad, brillantor, silenci, Jog Dial
+Keywords[cs]=IBM,Thinkpad,jas,ztlumení,Jog Dial
+Keywords[cy]=IBM,Thinkpad,gloywder, mud, Jog Dial
+Keywords[da]=IBM. Thinkpad, lysstyrke, stum, Jog Dial
+Keywords[de]=IBM, Thinkpad, Helligkeit, Abschalten, Jog Dial
+Keywords[el]=IBM, Thinkpad, φωτεινότητα, κλείσιμο ήχου, Jog Dial
+Keywords[es]=IBM, Thinkpad, brillo, mute, Jog Dial
+Keywords[et]=IDM, Thinkpad, heledus, tumm, Jog Dial
+Keywords[eu]=IBM, Thinkpad, distira, mutu, Jog Dial
+Keywords[fa]=IBM، Thinkpad، روشنایی، بدون صدا، Jog Dial
+Keywords[fi]=IBM, Thinkpad, kirkkaus, vaimenna, Jog Dial
+Keywords[fr]=IBM, Thinkpad, luminosité, sourdine, mute, Jog Dial
+Keywords[ga]=IBM, Thinkpad, gile, gan fuaim, Jog Dial
+Keywords[hu]=IBM,Thinkpad,fényerő,elnémítás,tárcsagomb
+Keywords[it]=IBM,Thinkpad,luminosità,muto,Jog Dial
+Keywords[ja]=IBM, シンクパッド, 明るさ, ミュート, ジョグダイアル
+Keywords[mk]=IBM, Thinkpad, brightness, mute, Jog Dial, осветленост, пригушување
+Keywords[nb]=IBM, Thinkpad, lysstyrke, dempet, Jog Dial
+Keywords[nds]=IBM, Thinkpad, Helligkeit, stumm, Jog Dial
+Keywords[ne]=IBM, थिङ्कप्याड, चम्किलोपना, चुप लाग्नु, जोग डायल
+Keywords[nl]=IBM, Thinkpad, brightness, mute, Jog Dial, Helderheid, dempen
+Keywords[nn]=IBM,Thinkpad,lysstyrke,demping,snurrehjul
+Keywords[pa]=IBM, Thinkpad, brightness, mute, Jog Dial, ਲੈਪਟਾਪ
+Keywords[pl]=IBM, Thinkpad, jasność, wycisz, Jog Dial
+Keywords[pt]=IBM, Thinkpad, brilho, sem som, Jog Dial
+Keywords[pt_BR]=IBM,Thinkpad,brilho, mudo, Jog Dial
+Keywords[ro]=IBM,Thinkpad,strălucire,fără sunet,jog dial
+Keywords[ru]=IBM, Thinkpad, brightness, mute, Jog Dial, яркость, звук
+Keywords[sk]=IBM, Thinkpad,jas,potichu
+Keywords[sl]=IBM, Thinkpad, svetlost, tiho, Jog Dial
+Keywords[sr]=Sony, Vaio, kvaio, brightness, mute, Jog Dial, светлина
+Keywords[sr@Latn]=Sony, Vaio, kvaio, brightness, mute, Jog Dial, svetlina
+Keywords[sv]=IBM, Thinkpad, ljusstyrka, tyst, rullhjul
+Keywords[ta]=ஐபிஎம், திங்க்பேட்,ஒளித்தன்மை,ஓசையற்ற,ஜோக் டையல்
+Keywords[tr]=IBM, Thinkpad, parlaklık, sessiz, gösterme itmesi
+Keywords[uk]=IBM, Thinkpad, яскравість, вимкнення звуку, Jog Dial
+Keywords[zh_CN]=IBM, Lenovo, Thinkpad, brightness, mute, Jog Dial,亮度,静音,联想,导航键
+
+Categories=Qt;KDE;X-KDE-settings-system;
diff --git a/kmilo/thinkpad/kmilo_thinkpad.desktop b/kmilo/thinkpad/kmilo_thinkpad.desktop
new file mode 100644
index 0000000..1d957c4
--- /dev/null
+++ b/kmilo/thinkpad/kmilo_thinkpad.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KMilo Plugin
+X-KDE-ModuleType=Plugin
+Name=Thinkpad Plugin
+Name[ar]=ملحق Thinkpad
+Name[br]=Lugent Thinkpad
+Name[bs]=Thinkpad dodatak
+Name[ca]=Connector Thinkpad
+Name[cs]=Thinkpad modul
+Name[cy]=Ategyn Thinkpad
+Name[de]=Thinkpad-Plugin
+Name[el]=Πρόσθετο Thinkpad
+Name[eo]=Thinkpad-kromaĵo
+Name[es]=Extensión para Thinkpad
+Name[et]=Thinkpadi plugin
+Name[eu]=Thikpad Plugina
+Name[fa]=Thinkpad وصلۀ
+Name[fi]=Thinkpad-liitännäinen
+Name[fr]=Module externe pour les Thinkpad
+Name[ga]=Breiseán Thinkpad
+Name[he]=תוסף ל-Thinkpad
+Name[hu]=Thinkpad bővítőmodul
+Name[is]=Thinkpad íforrit
+Name[it]=Plugin Thinkpad
+Name[ja]=シンクパッド プラグイン
+Name[ka]=Thinkpad-ის მოდული
+Name[kk]=Thinkpad модулі
+Name[km]=កម្មវិធី​ជំនួយ Thinkpad Plugin
+Name[lt]=Thinkpad priedas
+Name[mk]=Приклучок за Thinkpad
+Name[nb]=Thinkpad tilleggs program
+Name[nds]=Thinkpad-Moduul
+Name[ne]=थिङ्कप्याड प्लगइन
+Name[nn]=Programtillegg for Thinkpad
+Name[pa]=Thinkpad ਪਲੱਗਿੰਨ
+Name[pl]=Wtyczka Thinkpad
+Name[pt]='Plugin' para Thinkpad
+Name[pt_BR]=Plugin do Thinkpad
+Name[ro]=Modul Thinkpad
+Name[ru]=Модуль Thinkpad
+Name[sk]=Modul pre Thinkpad
+Name[sl]=Vstavek za Thinkpad
+Name[sr]=Прикључак за Thinkpad
+Name[sr@Latn]=Priključak za Thinkpad
+Name[sv]=Thinkpad-insticksprogram
+Name[ta]=திங்க்பேட் செருகி
+Name[tr]=Thinkpad Eklentisi
+Name[uk]=Втулок Thinkpad
+Name[uz]=Thinkpad plagini
+Name[uz@cyrillic]=Thinkpad плагини
+Name[zh_CN]=Thinkpad 插件
+Name[zh_TW]=Thinkpad 外掛程式
+Comment=Enables support for special Thinkpad keys
+Comment[ar]=تمكّن الدعم لمفاتيح Thinkpad الخاصة
+Comment[bg]=Тази приставка позволява поддръжката на специалните клавиши на IBM Thinkpad
+Comment[bs]=Omogućuje podršku za posebne tipke na Thinkpadu
+Comment[ca]=Habilita el funcionament per a tecles especials de Thinkpad
+Comment[cs]=Umožňuje podporu speciálních kláves Thinkpadu
+Comment[cy]=Yn galluogi cynhaliaeth ar gyfer bysyll arbennig Thinkpad
+Comment[da]=Aktiverer støtte for specielle Thinkpad taster
+Comment[de]=Dieses Plugin aktiviert die Unterstützung für Sondertasten von Thinkpad-Tastaturen
+Comment[el]=Ενεργοποιεί την υποστήριξη για ειδικά πλήκτρα του Thinkpad
+Comment[es]=Activa el soporte de las teclas especiales del Thinkpad
+Comment[et]=See plugin võimaldab kasutada Thinkpadi eriklahve.
+Comment[eu]=Thinkpad-en tekla berezientzako euskarria gaitzen du
+Comment[fa]=فعال‌سازی پشتیبانی برای کلیدهای ویژۀ Thinkpad .
+Comment[fi]=Tämä liitännäinen mahdollistaa erikoisnäppäinten tuen IBM Thinkpad kannettaville tietokoneille.
+Comment[fr]=Ce module active la gestion des touches spéciales des Thinkpad.
+Comment[ga]=Tacaigh le heochracha speisialta Thinkpad
+Comment[he]=מאפשר תמיכה במקשים מיוחדים של Thinkpad
+Comment[hu]=Ez a bővítőmodul lehetővé teszi az IBM Thinkpad noteszgépek speciális billentyűinek használatát
+Comment[is]=Virkjar stuðning fyrir sérhnappa Thinkpad véla
+Comment[it]=Abilita il supporto per i tasti speciali Thinkpad
+Comment[ja]=シンクパッドの特殊キーをサポートします
+Comment[ka]=რთავს Thinkpad-ის სპეციალური კლავიშების მხარდაჭერას
+Comment[kk]=Thinkpad-тың арнаулы пернелерін қолдауы
+Comment[km]=បើក​ការគាំទ្រ​សម្រាប់​គ្រាប់ចុច Thinkpad ពិសេស
+Comment[lt]=įgalina ypatingų Thinkpad raktų paramą
+Comment[mk]=Овозможува поддршка за спец. копчиња на Thinkpad
+Comment[nb]=Dette programtillegget muliggjør støtte for spesielle taster på alle tastatur og bærbare maskiner
+Comment[nds]=Maakt de Sünnertasten-Ünnerstütten för Thinkpads an
+Comment[ne]=विशेष थिङ्कप्याड कुञ्जीका लागि समर्थन सक्षम पार्दछ
+Comment[nl]=Activeert de ondersteuning voor spciale Thinkpad-toetsen
+Comment[nn]=Dette programtillegget gjer det mogleg å bruka spesialtastar på Thinkpad
+Comment[pl]=Włącza obsługę specjalnych klawiszy Thinkpada
+Comment[pt]=Activa o suporte a teclas especiais do Thinkpad
+Comment[pt_BR]=Habilita suporte para teclas especiais no Thinkpad
+Comment[ro]=Activează suportul pentru tastele speciale Thinkpad
+Comment[ru]=Этот модуль поддерживает специальные клавиши Thinkpad
+Comment[sk]=Zapína podporu pre špeciálne klávesy notebookov Thinkpad
+Comment[sl]=Omogoči podporo posebnim tipkam Thinkpada
+Comment[sr]=Подршку за посебне Thinkpad-ове тастере
+Comment[sr@Latn]=Podršku za posebne Thinkpad-ove tastere
+Comment[sv]=Aktiverar stöd för speciella Thinkpad-tangenter
+Comment[ta]=விசேஷ திங்க்பேட் விசைகளுக்கான ஆதரவை செயல்படுத்துகிறது
+Comment[tr]=Özel Thinkpad tuşları için desteği etkinleştirir
+Comment[uk]=Уможливлює підтримку спеціальних клавіш для Thinkpad.
+Comment[zh_CN]=此插件启用各种键盘和便携电脑的特殊按键
+Comment[zh_TW]=開啟特殊 Thinkpad 按鍵支援
+X-KDE-Library=kmilo_thinkpad
diff --git a/kmilo/thinkpad/thinkpad.cpp b/kmilo/thinkpad/thinkpad.cpp
new file mode 100644
index 0000000..74770cf
--- /dev/null
+++ b/kmilo/thinkpad/thinkpad.cpp
@@ -0,0 +1,556 @@
+/*
+ This file is part of the KDE project
+
+ Copyright (c) 2004 Jonathan Riddell <jr@jriddell.org>
+
+ Based on Demo kmilo service by George Staikos
+ Copyright (c) 2003 George Staikos <staikos@kde.org>
+
+ And tpb by Markus Braun
+ Copyright (C) 2002,2003 Markus Braun <markus.braun@krawel.de>
+
+ FreeBSD support by Markus Brueffer
+ Copyright (C) 2005 Markus Brueffer <markus@FreeBSD.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <kgenericfactory.h>
+#include <kconfig.h>
+#include <krun.h>
+#include <kurl.h>
+#include "kmilointerface.h"
+
+#ifdef Q_OS_FREEBSD
+#include <sys/sysctl.h>
+#endif
+
+#include "thinkpad.h"
+
+namespace KMilo {
+
+ThinkPadMonitor::ThinkPadMonitor(QObject* parent, const char* name, const QStringList& args): Monitor(parent, name, args) {
+ m_progress = 0;
+ m_volume = 50; //set in retrieveVolume()
+}
+
+ThinkPadMonitor::~ThinkPadMonitor() {
+}
+
+bool ThinkPadMonitor::init() {
+
+ KConfig config("kmilodrc");
+ reconfigure(&config);
+
+ if (m_run) {
+ clearStruct(thinkpad_state);
+ clearStruct(last_thinkpad_state);
+ if ( getNvramState(&thinkpad_state) == false ) {
+ return false;
+ }
+
+ if (m_softwareVolume || m_volumeStep != defaultVolumeStep) {
+ kmixClient = new DCOPRef("kmix", "Mixer0");
+ kmixWindow = new DCOPRef("kmix", "kmix-mainwindow#1");
+ retrieveVolume();
+ setNvramVolume();
+ }
+ }
+
+ return m_run;
+}
+
+Monitor::DisplayType ThinkPadMonitor::poll() {
+
+ // save last state and get new one
+ memcpy(&last_thinkpad_state, &thinkpad_state, sizeof(thinkpad_state_struct));
+ getNvramState(&thinkpad_state);
+
+ Monitor::DisplayType pollResult = None;
+
+ // determine the state of the mute button
+ if (thinkpad_state.mute_toggle != last_thinkpad_state.mute_toggle ||
+ (thinkpad_state.volume_toggle != last_thinkpad_state.volume_toggle
+ && last_thinkpad_state.mute_toggle == 1)) {
+
+ showToggleMessage(i18n("Mute on"), i18n("Mute off"), thinkpad_state.mute_toggle == 1);
+ if (m_softwareVolume || m_volumeStep != defaultVolumeStep) {
+ kmixClient->send("setMasterMute", thinkpad_state.mute_toggle == 1);
+ }
+ }
+
+ // determine the state of the Thinkpad button
+ if (thinkpad_state.thinkpad_toggle != last_thinkpad_state.thinkpad_toggle &&
+ thinkpad_state.hibernate_toggle == last_thinkpad_state.hibernate_toggle) {
+ _interface->displayText(i18n("Thinkpad Button Pressed"));
+
+ KURL url(m_buttonThinkpad);
+ (void) new KRun(url, 0, true, true);
+ }
+
+ // determine the state of ThinkLight
+ if (thinkpad_state.thinklight_toggle != last_thinkpad_state.thinklight_toggle) {
+ showToggleMessage(i18n("ThinkLight is on"), i18n("ThinkLight is off"), thinkpad_state.thinklight_toggle == 1);
+ }
+
+ // determine the state of the volume buttons
+ if (thinkpad_state.volume_level != last_thinkpad_state.volume_level) {
+
+ pollResult = Volume;
+
+ if (m_volumeStep == defaultVolumeStep && m_softwareVolume == false) {
+ //no need to write to nvram or set volume in software
+ m_progress = thinkpad_state.volume_level * 100 / defaultVolumeStep;
+ } else {
+ if (thinkpad_state.volume_level > last_thinkpad_state.volume_level) {
+ m_progress = m_volume + m_volumeStep;
+ } else {
+ m_progress = m_volume - m_volumeStep;
+ }
+ setVolume(m_progress);
+ }
+
+ }
+
+ // determine the state of the brightness buttons
+ if (thinkpad_state.brightness_level != last_thinkpad_state.brightness_level) {
+ pollResult = Brightness;
+ m_progress = thinkpad_state.brightness_level * 100 / 7;
+ }
+
+ // Buttons below here are untested because they do not exist on my R31
+
+ // determine the state of zoom
+ if (thinkpad_state.zoom_toggle != last_thinkpad_state.zoom_toggle) {
+ // showToggleMessage(i18n("Zoom is on"), i18n("Zoom is off"), thinkpad_state.zoom_toggle == 1);
+
+ // Use as button since an Zooming is implemented
+ _interface->displayText(i18n("Zoom button pressed"));
+
+ KURL url(m_buttonZoom);
+ (void) new KRun(url, 0, true, true);
+ }
+
+ // determine the state of the home button
+ if (thinkpad_state.home_toggle != last_thinkpad_state.home_toggle &&
+ thinkpad_state.hibernate_toggle == last_thinkpad_state.hibernate_toggle) {
+ _interface->displayText(i18n("Home button pressed"));
+ KURL url(m_buttonHome);
+ (void) new KRun(url, 0, true, true);
+ }
+
+ // determine the state of the search button
+ if (thinkpad_state.search_toggle != last_thinkpad_state.search_toggle &&
+ thinkpad_state.hibernate_toggle == last_thinkpad_state.hibernate_toggle) {
+ _interface->displayText(i18n("Search button pressed"));
+ KURL url(m_buttonSearch);
+ (void) new KRun(url, 0, true, true);
+ }
+
+ // determine the state of the mail button
+ if (thinkpad_state.mail_toggle != last_thinkpad_state.mail_toggle &&
+ thinkpad_state.hibernate_toggle == last_thinkpad_state.hibernate_toggle) {
+ _interface->displayText(i18n("Mail button pressed"));
+ KURL url(m_buttonMail);
+ (void) new KRun(url, 0, true, true);
+ }
+
+ // determine the state of display
+ if (thinkpad_state.display_toggle != last_thinkpad_state.display_toggle &&
+ thinkpad_state.hibernate_toggle == last_thinkpad_state.hibernate_toggle) {
+
+ // Some thinkpads have no hardware support to switch lcd/crt. They also
+ // don't reflect the current state in thinkpad_state.display_state. So, if
+ // thinkpad_state.display_toggle changes, but thinkpad_state.display_state does
+ // not change, simulate the display state.
+
+ unsigned int display_state = 1;
+ if (thinkpad_state.display_state == last_thinkpad_state.display_state) {
+ display_state = display_state % 3 + 1;
+ } else {
+ display_state = thinkpad_state.display_state;
+ }
+
+ switch (display_state & 0x03) {
+ case 0x1:
+ _interface->displayText(i18n("Display changed: LCD on, CRT off"));
+ break;
+
+ case 0x2:
+ _interface->displayText(i18n("Display changed: LCD off, CRT on"));
+ break;
+
+ case 0x3:
+ _interface->displayText(i18n("Display changed: LCD on, CRT on"));
+ break;
+ }
+ }
+
+ // determine the state of hv expansion
+ if (thinkpad_state.expand_toggle != last_thinkpad_state.expand_toggle) {
+ showToggleMessage(i18n("HV Expansion is on"), i18n("HV Expansion is off"), (thinkpad_state.expand_toggle & 0x01) == 1);
+ }
+
+ // determine power management mode AC
+ if (thinkpad_state.powermgt_ac != last_thinkpad_state.powermgt_ac) {
+ switch(thinkpad_state.powermgt_ac) {
+ case 0x4:
+ _interface->displayText(i18n("Power management mode AC changed: PM AC high"));
+ break;
+
+ case 0x2:
+ _interface->displayText(i18n("Power management mode AC changed: PM AC auto"));
+ break;
+
+ case 0x1:
+ _interface->displayText(i18n("Power management mode AC changed: PM AC manual"));
+ break;
+
+ default:
+ _interface->displayText(i18n("Power management mode AC changed: PM AC unknown"));
+ break;
+ }
+ }
+
+ // determine power management mode battery
+ if (thinkpad_state.powermgt_battery != last_thinkpad_state.powermgt_battery) {
+ switch(thinkpad_state.powermgt_battery) {
+ case 0x4:
+ _interface->displayText(i18n("Power management mode battery changed: PM battery high"));
+ break;
+
+ case 0x2:
+ _interface->displayText(i18n("Power management mode battery changed: PM battery auto"));
+ break;
+
+ case 0x1:
+ _interface->displayText(i18n("Power management mode battery changed: PM battery manual"));
+ break;
+
+ default:
+ _interface->displayText(i18n("Power management mode battery changed: PM battery unknown"));
+ break;
+ }
+ }
+
+ // determine the state of wireless lan
+ if (thinkpad_state.wireless_toggle != last_thinkpad_state.wireless_toggle) {
+ showToggleMessage(i18n("Wireless LAN is enabled"), i18n("Wireless LAN is disabled"), thinkpad_state.wireless_toggle == 1);
+ }
+
+ // determine the state of bluetooth
+ if (thinkpad_state.bluetooth_toggle != last_thinkpad_state.bluetooth_toggle) {
+ showToggleMessage(i18n("Bluetooth is enabled"), i18n("Bluetooth is disabled"), thinkpad_state.bluetooth_toggle == 1);
+ }
+
+ return pollResult;
+}
+
+
+int ThinkPadMonitor::progress() const {
+ return m_progress;
+}
+
+QString ThinkPadMonitor::message() const {
+ //unused
+ //return i18n("yer maw!");
+ return "";
+}
+
+bool ThinkPadMonitor::getNvramState(thinkpad_state_struct* thinkpad_state) {
+#ifndef Q_OS_FREEBSD
+ int file;
+ unsigned char buffer[114];
+
+ // open nvram for reading
+ // must use open/close because seek is not supported by nvram
+ if ((file=open(m_nvramFile.latin1(), O_RDONLY|O_NONBLOCK)) == -1) {
+ kdError() << "Unable to open device: " << m_nvramFile << endl;
+ return false;
+ }
+
+ // read nvram
+ if (read(file, buffer, sizeof(buffer)) != sizeof(buffer)) {
+ kdError() << "Unable to read from device: " << m_nvramFile << endl;
+ return false;
+ }
+
+ // close nvram device
+ if (close(file) == -1) {
+ kdError() << "Unable to close device %s: " << m_nvramFile << endl;
+ return false;
+ }
+
+ thinkpad_state->thinkpad_toggle
+ = (thinkpad_state->thinkpad_toggle & ~0x01) | (( buffer[0x57] & 0x08) >> 3);
+ thinkpad_state->zoom_toggle
+ = (thinkpad_state->zoom_toggle & ~0x01) | ((~buffer[0x57] & 0x20) >> 5);
+ thinkpad_state->display_toggle
+ = (thinkpad_state->display_toggle & ~0x01) | (( buffer[0x57] & 0x40) >> 6);
+ thinkpad_state->home_toggle
+ = (thinkpad_state->home_toggle & ~0x01) | (( buffer[0x56] & 0x01) );
+ thinkpad_state->search_toggle
+ = (thinkpad_state->search_toggle & ~0x01) | (( buffer[0x56] & 0x02) >> 1);
+ thinkpad_state->mail_toggle
+ = (thinkpad_state->mail_toggle & ~0x01) | (( buffer[0x56] & 0x04) >> 2);
+ thinkpad_state->thinklight_toggle
+ = (thinkpad_state->thinklight_toggle & ~0x01) | (( buffer[0x58] & 0x10) >> 4);
+ thinkpad_state->hibernate_toggle
+ = (thinkpad_state->hibernate_toggle & ~0x01) | (( buffer[0x58] & 0x01) );
+ thinkpad_state->display_state
+ = (( buffer[0x59] & 0x03) );
+ thinkpad_state->expand_toggle
+ = (thinkpad_state->expand_toggle & ~0x01) | (( buffer[0x59] & 0x10) >> 4);
+ thinkpad_state->brightness_level
+ = (( buffer[0x5E] & 0x07) );
+ thinkpad_state->brightness_toggle
+ = (thinkpad_state->brightness_toggle & ~0x01) | (( buffer[0x5E] & 0x20) >> 5);
+ thinkpad_state->volume_level
+ = (( buffer[0x60] & 0x0f) );
+ thinkpad_state->volume_toggle
+ = (thinkpad_state->volume_toggle & ~0x01) | (( buffer[0x60] & 0x80) >> 7);
+ thinkpad_state->mute_toggle
+ = (thinkpad_state->mute_toggle & ~0x01) | (( buffer[0x60] & 0x40) >> 6);
+ thinkpad_state->powermgt_ac
+ = (( buffer[0x39] & 0x07) );
+ thinkpad_state->powermgt_battery
+ = (( buffer[0x39] & 0x38) >> 3);
+#else
+ u_int n = 0;
+ size_t len = sizeof(n);
+
+ if ( sysctlbyname("dev.acpi_ibm.0.hotkey", &n, &len, NULL, 0) == -1 ) {
+ kdError() << "Unable to read sysctl: dev.acpi_ibm.0.hotkey" << endl;
+ return false;
+ }
+
+ thinkpad_state->thinkpad_toggle
+ = (thinkpad_state->thinkpad_toggle & ~0x01) | (( n & (1<<3)) >> 3);
+ thinkpad_state->zoom_toggle
+ = (thinkpad_state->zoom_toggle & ~0x01) | (( n & (1<<4)) >> 4);
+ thinkpad_state->display_toggle
+ = (thinkpad_state->display_toggle & ~0x01) | (( n & (1<<6)) >> 6);
+ thinkpad_state->home_toggle
+ = (thinkpad_state->home_toggle & ~0x01) | (( n & (1<<0)) );
+ thinkpad_state->search_toggle
+ = (thinkpad_state->search_toggle & ~0x01) | (( n & (1<<1)) >> 1);
+ thinkpad_state->mail_toggle
+ = (thinkpad_state->mail_toggle & ~0x01) | (( n & (1<<2)) >> 2);
+ thinkpad_state->hibernate_toggle
+ = (thinkpad_state->hibernate_toggle & ~0x01) | (( n & (1<<7)) >> 7);
+ thinkpad_state->expand_toggle
+ = (thinkpad_state->expand_toggle & ~0x01) | (( n & (1<<9)) >> 9);
+ thinkpad_state->brightness_toggle
+ = (thinkpad_state->brightness_toggle & ~0x01) | (( n & (1<<10)) >> 10);
+ thinkpad_state->volume_toggle
+ = (thinkpad_state->volume_toggle & ~0x01) | (( n & (1<<11)) >> 11);
+
+ // Don't fail if the thinklight sysctl is not present. It is generated dynamically
+ if ( sysctlbyname("dev.acpi_ibm.0.thinklight", &n, &len, NULL, 0) != -1 )
+ thinkpad_state->thinklight_toggle = n;
+ else
+ kdWarning() << "Unable to read sysctl: dev.acpi_ibm.0.thinklight" << endl;
+
+ if ( sysctlbyname("dev.acpi_ibm.0.lcd_brightness", &n, &len, NULL, 0) == -1 ) {
+ kdError() << "Unable to read sysctl: dev.acpi_ibm.0.lcd_brightness" << endl;
+ return false;
+ }
+ thinkpad_state->brightness_level = n;
+
+ if ( sysctlbyname("dev.acpi_ibm.0.volume", &n, &len, NULL, 0) == -1 ) {
+ kdError() << "Unable to read sysctl: dev.acpi_ibm.0.volume" << endl;
+ return false;
+ }
+ thinkpad_state->volume_level = n;
+
+ if ( sysctlbyname("dev.acpi_ibm.0.mute", &n, &len, NULL, 0) == -1 ) {
+ kdError() << "Unable to read sysctl: dev.acpi_ibm.0.mute" << endl;
+ return false;
+ }
+ thinkpad_state->mute_toggle = n;
+
+ // Don't fail if wlan or bluetooth sysctls are not present. They are generated dynamically
+ if ( sysctlbyname("dev.acpi_ibm.0.wlan", &n, &len, NULL, 0) != -1 )
+ thinkpad_state->wireless_toggle = n;
+ else
+ kdWarning() << "Unable to read sysctl: dev.acpi_ibm.0.wlan" << endl;
+
+ if ( sysctlbyname("dev.acpi_ibm.0.bluetooth", &n, &len, NULL, 0) != -1 )
+ thinkpad_state->bluetooth_toggle = n;
+ else
+ kdWarning() << "Unable to read sysctl: dev.acpi_ibm.0.bluetooth" << endl;
+#endif
+ return true;
+}
+
+void ThinkPadMonitor::clearStruct(thinkpad_state_struct& thinkpad_state) {
+ thinkpad_state.thinkpad_toggle = 0;
+ thinkpad_state.zoom_toggle = 0;
+ thinkpad_state.display_toggle = 0;
+ thinkpad_state.home_toggle = 0;
+ thinkpad_state.search_toggle = 0;
+ thinkpad_state.mail_toggle = 0;
+ thinkpad_state.favorites_toggle = 0;
+ thinkpad_state.reload_toggle = 0;
+ thinkpad_state.abort_toggle = 0;
+ thinkpad_state.backward_toggle = 0;
+ thinkpad_state.forward_toggle = 0;
+ thinkpad_state.fn_toggle = 0;
+ thinkpad_state.thinklight_toggle = 0;
+ thinkpad_state.hibernate_toggle = 0;
+ thinkpad_state.display_state = 0;
+ thinkpad_state.expand_toggle = 0;
+ thinkpad_state.brightness_level = 0;
+ thinkpad_state.brightness_toggle = 0;
+ thinkpad_state.volume_level = 0;
+ thinkpad_state.volume_toggle = 0;
+ thinkpad_state.mute_toggle = 0;
+ thinkpad_state.ac_state = 0;
+ thinkpad_state.powermgt_ac = 0;
+ thinkpad_state.powermgt_battery = 0;
+ thinkpad_state.wireless_toggle = 0;
+ thinkpad_state.bluetooth_toggle = 0;
+}
+
+void ThinkPadMonitor::showToggleMessage(QString onMessage, QString offMessage, bool state) {
+ QString message;
+ if (state) {
+ message = onMessage;
+ } else {
+ message = offMessage;
+ }
+ _interface->displayText(message);
+}
+
+void ThinkPadMonitor::reconfigure(KConfig* config) {
+ config->setGroup("thinkpad");
+
+ m_nvramFile = config->readEntry("nvram", "/dev/nvram");
+ m_softwareVolume = config->readBoolEntry("softwareVolume", true);
+ m_run = config->readBoolEntry("run", false);
+ m_volumeStep = config->readNumEntry("volumeStep", defaultVolumeStep);
+ m_buttonThinkpad = config->readEntry("buttonThinkpad", "/usr/bin/konsole");
+ m_buttonHome = config->readEntry("buttonHome", "/usr/bin/konqueror");
+ m_buttonSearch = config->readEntry("buttonSearch", "/usr/bin/kfind");
+ m_buttonMail = config->readEntry("buttonMail", "/usr/bin/kmail");
+ m_buttonZoom = config->readEntry("buttonZoom", "/usr/bin/ksnapshot");
+}
+
+bool ThinkPadMonitor::retrieveVolume() {
+ bool kmix_error = false;
+
+ DCOPReply reply = kmixClient->call("masterVolume");
+ if (reply.isValid()) {
+ m_volume = reply;
+ } else {
+ kmix_error = true;
+ }
+
+ if (kmix_error) { // maybe the error occurred because kmix wasn't running
+ if (kapp->startServiceByDesktopName("kmix")==0) { // trying to start kmix
+ // trying again
+ reply = kmixClient->call("masterVolume");
+ if (reply.isValid()) {
+ m_volume = reply;
+ kmix_error = false;
+ kmixWindow->send("hide");
+ }
+ }
+ }
+
+ if (kmix_error) {
+ kdError() << "KMilo: ThinkPadMonitor could not access kmix/Mixer0 via dcop" << endl;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void ThinkPadMonitor::setVolume(int volume) {
+ if (!retrieveVolume()) {
+ return;
+ }
+
+ if (volume > 100) {
+ m_volume = 100;
+ } else if (volume < 0) {
+ m_volume = 0;
+ } else {
+ m_volume = volume;
+ }
+ kmixClient->send("setMasterVolume", m_volume);
+
+ //write back to nvram but only if volume steps is not default
+ if (m_volumeStep != defaultVolumeStep) {
+ setNvramVolume();
+ }
+ m_progress = m_volume;
+}
+
+void ThinkPadMonitor::setNvramVolume() {
+#ifndef Q_OS_FREEBSD
+ int file;
+ char buffer;
+
+ //open nvram
+ if ((file = open(m_nvramFile.latin1(), O_RDWR|O_NONBLOCK)) == -1) {
+ kdError() << "Unable to open device " << m_nvramFile << endl;
+ return;
+ }
+
+ // jump to volume section
+ if (lseek(file, 0x60, SEEK_SET) == -1 ) {
+ kdError() << "Unable to seek device " << m_nvramFile << endl;
+ return;
+ }
+
+ // read nvram
+ if (read(file, &buffer, sizeof(buffer)) != sizeof(buffer)) {
+ kdError() << "Unable to read from device " << m_nvramFile << endl;
+ return;
+ }
+
+ // set volume_level to the value we write back to nvram
+ // taken from tpb, unfortunatly I'm not sure why it works
+ thinkpad_state.volume_level = 0x07;
+ buffer &= 0xf0;
+ buffer |= thinkpad_state.volume_level;
+
+ // jump to volume section
+ if (lseek(file, 0x60, SEEK_SET) == -1 ) {
+ kdError() << "Unable to seek device " << m_nvramFile << endl;
+ return;
+ }
+
+ // write std value for volume
+ if (write(file, &buffer, sizeof(buffer)) != sizeof(buffer)) {
+ kdError() << "Unable to write to device " << m_nvramFile << endl;
+ return;
+ }
+
+ close(file);
+#else
+ u_int n = thinkpad_state.volume_level;
+
+ if (sysctlbyname("dev.acpi_ibm.0.volume", NULL, NULL, &n, sizeof(n)))
+ kdError() << "Unable to write sysctl: dev.acpi_ibm.0.volume" << endl;
+#endif
+}
+
+}
+
+K_EXPORT_COMPONENT_FACTORY(kmilo_thinkpad, KGenericFactory<KMilo::ThinkPadMonitor>("kmilo_thinkpad"))
diff --git a/kmilo/thinkpad/thinkpad.h b/kmilo/thinkpad/thinkpad.h
new file mode 100644
index 0000000..f195b2e
--- /dev/null
+++ b/kmilo/thinkpad/thinkpad.h
@@ -0,0 +1,208 @@
+/*
+ This file is part of the KDE project
+
+ Copyright (c) 2004 Jonathan Riddell <jr@jriddell.org>
+
+ Based on Demo kmilo service by George Staikos
+ Copyright (c) 2003 George Staikos <staikos@kde.org>
+
+ And tpb by Markus Braun http://www.nongnu.org/tpb/
+ Copyright (C) 2002,2003 Markus Braun <markus.braun@krawel.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+#ifndef _THINKPAD_H_
+#define _THINKPAD_H_
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <kapplication.h>
+#include <dcopref.h>
+
+#include "monitor.h"
+
+namespace KMilo {
+
+
+const int defaultVolumeStep = 14;
+
+// all nvram toggle values are stored in bit 0
+// all xevents toggle values are stored in bit 1
+// xevent and apm toggles are not used, kept for compatibility with tpb
+typedef struct {
+ unsigned int thinkpad_toggle; // ThinkPad button
+ unsigned int zoom_toggle; // zoom toggle
+ unsigned int display_toggle; // display toggle
+ unsigned int home_toggle; // Home button
+ unsigned int search_toggle; // Search button
+ unsigned int mail_toggle; // Mail button
+ unsigned int favorites_toggle; // Favorites button (xevent)
+ unsigned int reload_toggle; // Reload button (xevent)
+ unsigned int abort_toggle; // Abort button (xevent)
+ unsigned int backward_toggle; // Backward button (xevent)
+ unsigned int forward_toggle; // Forward button (xevent)
+ unsigned int fn_toggle; // Fn button (xevent)
+ unsigned int thinklight_toggle; // ThinkLight
+ unsigned int hibernate_toggle; // hibernation/suspend toggle
+ unsigned int display_state; // display state
+ unsigned int expand_toggle; // hv expansion state
+ unsigned int brightness_level; // brightness level
+ unsigned int brightness_toggle; // brightness toggle
+ unsigned int volume_level; // volume level
+ unsigned int volume_toggle; // volume toggle
+ unsigned int mute_toggle; // mute toggle
+ unsigned int ac_state; // ac connected (apm)
+ unsigned int powermgt_ac; // power management mode ac
+ unsigned int powermgt_battery; // power management mode battery
+ unsigned int wireless_toggle; // wireless lan toggle
+ unsigned int bluetooth_toggle; // bluetooth toggle
+} thinkpad_state_struct;
+
+/**
+ * KMilo plugin for IBM Thinkpads
+ * Requires read access of nvram: insmod nvram; mknod /dev/nvram c 10 144; chmod 664 /dev/nvram
+ *
+ * Models R31 and R30 do not have hardware mixers, other models
+ * probably want a smaller volume change than thinkpad's default, for
+ * this you need write access to nvram: chmod 666 /dev/nvram
+ */
+class ThinkPadMonitor : public Monitor {
+ public:
+ ThinkPadMonitor(QObject *parent, const char *name, const QStringList&);
+ virtual ~ThinkPadMonitor();
+
+ /**
+ * Reimplemented from KMilo::Monitor.
+ * Loads configuration, clears struct, sets volume if necessary.
+ */
+ virtual bool init();
+
+ /**
+ * Reimplemented from KMilo::Monitor.
+ * Called by KMilo, this checks the nvram and acts on any changes
+ */
+ virtual DisplayType poll();
+
+ /**
+ * Reimplemented from KMilo::Monitor.
+ * Called by KMilo if poll() returns a volume or brightness change.
+ * Returns the new volume or brightness percentage.
+ */
+ virtual int progress() const;
+
+ /**
+ * Reimplemented from KMilo::Monitor.
+ * Not used, we just set the message ourselves using _interface->displayText()
+ */
+ virtual QString message() const;
+ protected:
+ /**
+ * Reimplemented from KMilo::Monitor.
+ * Loads configuration from kmilorc
+ */
+ virtual void reconfigure(KConfig*);
+ private:
+ /**
+ * get the current state from the nvram
+ */
+ bool getNvramState(thinkpad_state_struct* thinkpad_state);
+
+ /**
+ * get the current state from the nvram
+ */
+ void setNvramVolume();
+
+ /**
+ * set all values of thinkpad_state to zero
+ */
+ void clearStruct(thinkpad_state_struct& thinkpad_state);
+
+ /**
+ * Displays paramater message followed by 'on' or
+ * 'off' depending on state
+ */
+ void showToggleMessage(QString onMessage, QString offMessage, bool state);
+
+ /**
+ * Returned by progress()
+ */
+ int m_progress;
+
+ /**
+ * The file to read data from, default is /dev/nvram
+ */
+ QString m_nvramFile;
+
+ /**
+ * Some thinkpads change volume in hardware, others we
+ * have to do it ourselves
+ */
+ bool m_softwareVolume;
+
+ /**
+ * Config variable determines if this kmilo service is run or not
+ */
+ bool m_run;
+
+ /**
+ * Amount to change volume by each time, default is 14
+ * (as builtin to thinkpads)
+ */
+ int m_volumeStep;
+
+ /**
+ * Thinkpad button
+ */
+ QString m_buttonThinkpad;
+
+ /**
+ * Home button
+ */
+ QString m_buttonHome;
+
+ /**
+ * Search button
+ */
+ QString m_buttonSearch;
+
+ /**
+ * Mail button
+ */
+ QString m_buttonMail;
+
+ /**
+ * Zoom button
+ */
+ QString m_buttonZoom;
+
+ /**
+ * Used for changing the volume if m_softwareVolume is true
+ */
+ void setVolume(int volume);
+ DCOPRef* kmixClient;
+ DCOPRef* kmixWindow;
+ bool retrieveVolume();
+ int m_volume, m_oldVolume;
+
+ thinkpad_state_struct thinkpad_state;
+ thinkpad_state_struct last_thinkpad_state;
+};
+
+} //close namespace
+
+#endif