-rw-r--r-- | libopie2/opiecore/device/odevice.cpp | 623 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevice.h | 329 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevice_ipaq.cpp | 524 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevice_jornada.cpp | 214 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevice_ramses.cpp | 317 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevice_simpad.cpp | 443 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevice_yopy.cpp | 212 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevice_zaurus.cpp | 790 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevicebutton.cpp | 246 | ||||
-rw-r--r-- | libopie2/opiecore/device/odevicebutton.h | 108 | ||||
-rw-r--r-- | libopie2/opiecore/libopiecore2.control | 2 | ||||
-rw-r--r-- | libopie2/opiecore/opiecore.pro | 16 | ||||
-rw-r--r-- | libopie2/opiecore/oprocctrl.cpp | 284 | ||||
-rw-r--r-- | libopie2/opiecore/oprocctrl.h | 121 | ||||
-rw-r--r-- | libopie2/opiecore/oprocess.cpp | 970 | ||||
-rw-r--r-- | libopie2/opiecore/oprocess.h | 747 | ||||
-rw-r--r-- | libopie2/opienet/libopienet2.control | 4 |
17 files changed, 5946 insertions, 4 deletions
diff --git a/libopie2/opiecore/device/odevice.cpp b/libopie2/opiecore/device/odevice.cpp new file mode 100644 index 0000000..0f88c3c --- a/dev/null +++ b/libopie2/opiecore/device/odevice.cpp @@ -0,0 +1,623 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "odevice.h" + +/* QT */ +#include <qapplication.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qwindowsystem_qws.h> + +/* OPIE */ +#include <qpe/config.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> + +/* STD */ +#include <fcntl.h> +#include <math.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +using namespace Opie; + +class iPAQ; +class Zaurus; +class SIMpad; +class Ramses; +class Jornada; + +ODevice *ODevice::inst() +{ + static ODevice *dev = 0; + + // rewrite this to only use /proc/devinfo or so + + /* + if ( !dev ) { + if ( QFile::exists ( "/proc/hal/model" )) + dev = new iPAQ(); + else if ( Zaurus::isZaurus() ) + dev = new Zaurus(); + else if ( QFile::exists ( "/proc/ucb1x00" ) && QFile::exists ( "/proc/cs3" )) + dev = new SIMpad(); + else if ( QFile::exists ( "/proc/sys/board/name" )) + dev = new Ramses(); + else if ( Yopy::isYopy() ) + dev = new Yopy(); + else if ( Jornada::isJornada() ) + dev = new Jornada(); + else + dev = new ODevice(); + dev->init(); + } + */ + return dev; +} + +ODevice::ODevice() +{ + d = new ODeviceData; + + d->m_modelstr = "Unknown"; + d->m_model = Model_Unknown; + d->m_vendorstr = "Unknown"; + d->m_vendor = Vendor_Unknown; + d->m_systemstr = "Unknown"; + d->m_system = System_Unknown; + d->m_sysverstr = "0.0"; + d->m_rotation = Rot0; + d->m_direction = CW; + + d->m_holdtime = 1000; // 1000ms + d->m_buttons = 0; + d->m_cpu_frequencies = new QStrList; +} + +void ODevice::systemMessage ( const QCString &msg, const QByteArray & ) +{ + if ( msg == "deviceButtonMappingChanged()" ) { + reloadButtonMapping(); + } +} + +void ODevice::init() +{ +} + +/** +* This method initialises the button mapping +*/ +void ODevice::initButtons() +{ + if ( d->m_buttons ) + return; + + qDebug ( "init Buttons" ); + d->m_buttons = new QValueList <ODeviceButton>; + + reloadButtonMapping(); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); +} + +ODevice::~ODevice() +{ +// we leak m_devicebuttons and m_cpu_frequency +// but it's a singleton and it is not so importantant +// -zecke + delete d; +} + +bool ODevice::setSoftSuspend ( bool /*soft*/ ) +{ + return false; +} + +//#include <linux/apm_bios.h> + +#define APM_IOC_SUSPEND OD_IO( 'A', 2 ) + +/** +* This method will try to suspend the device +* It only works if the user is the QWS Server and the apm application +* is installed. +* It tries to suspend and then waits some time cause some distributions +* do have asynchronus apm implementations. +* This method will either fail and return false or it'll suspend the +* device and return once the device got woken up +* +* @return if the device got suspended +*/ +bool ODevice::suspend() +{ + qDebug("ODevice::suspend"); + if ( !isQWS( ) ) // only qwsserver is allowed to suspend + return false; + + if ( d->m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices + return false; + + bool res = false; + + struct timeval tvs, tvn; + ::gettimeofday ( &tvs, 0 ); + + ::sync(); // flush fs caches + res = ( ::system ( "apm --suspend" ) == 0 ); + + // This is needed because the iPAQ apm implementation is asynchronous and we + // can not be sure when exactly the device is really suspended + // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists. + + if ( res ) { + do { // wait at most 1.5 sec: either suspend didn't work or the device resumed + ::usleep ( 200 * 1000 ); + ::gettimeofday ( &tvn, 0 ); + } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 1500 ); + } + + return res; +} + +//#include <linux/fb.h> better not rely on kernel headers in userspace ... + +#define FBIOBLANK OD_IO( 'F', 0x11 ) // 0x4611 + +/* VESA Blanking Levels */ +#define VESA_NO_BLANKING 0 +#define VESA_VSYNC_SUSPEND 1 +#define VESA_HSYNC_SUSPEND 2 +#define VESA_POWERDOWN 3 + +/** +* This sets the display on or off +*/ +bool ODevice::setDisplayStatus ( bool on ) +{ + qDebug("ODevice::setDisplayStatus(%d)", on); + + if ( d->m_model == Model_Unknown ) + return false; + + bool res = false; + int fd; + + if (( fd = ::open ( "/dev/fb0", O_RDWR )) >= 0 ) { + res = ( ::ioctl ( fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN ) == 0 ); + ::close ( fd ); + } + return res; +} + +/** +* This sets the display brightness +* +* @param p The brightness to be set on a scale from 0 to 255 +* @return success or failure +*/ +bool ODevice::setDisplayBrightness ( int p) +{ + Q_UNUSED( p ) + return false; +} + +/** +* @return returns the number of steppings on the brightness slider +* in the Light-'n-Power settings. +*/ +int ODevice::displayBrightnessResolution() const +{ + return 16; +} + +/** +* This sets the display contrast +* @param p The contrast to be set on a scale from 0 to 255 +* @return success or failure +*/ +bool ODevice::setDisplayContrast ( int p) +{ + Q_UNUSED( p ) + return false; +} + +/** +* @return return the max value for the brightness settings slider +* or 0 if the device doesn't support setting of a contrast +*/ +int ODevice::displayContrastResolution() const +{ + return 0; +} + +/** +* This returns the vendor as string +* @return Vendor as QString +*/ +QString ODevice::vendorString() const +{ + return d->m_vendorstr; +} + +/** +* This returns the vendor as one of the values of OVendor +* @return OVendor +*/ +OVendor ODevice::vendor() const +{ + return d->m_vendor; +} + +/** +* This returns the model as a string +* @return A string representing the model +*/ +QString ODevice::modelString() const +{ + return d->m_modelstr; +} + +/** +* This does return the OModel used +*/ +OModel ODevice::model() const +{ + return d->m_model; +} + +/** +* This does return the systen name +*/ +QString ODevice::systemString() const +{ + return d->m_systemstr; +} + +/** +* Return System as OSystem value +*/ +OSystem ODevice::system() const +{ + return d->m_system; +} + +/** +* @return the version string of the base system +*/ +QString ODevice::systemVersionString() const +{ + return d->m_sysverstr; +} + +/** +* @return the current Transformation +*/ +Transformation ODevice::rotation() const +{ + return d->m_rotation; +} + +/** +* @return the current rotation direction +*/ +ODirection ODevice::direction() const +{ + return d->m_direction; +} + +/** +* This plays an alarmSound +*/ +void ODevice::alarmSound() +{ +#ifndef QT_NO_SOUND + static Sound snd ( "alarm" ); + + if ( snd. isFinished()) + snd. play(); +#endif +} + +/** +* This plays a key sound +*/ +void ODevice::keySound() +{ +#ifndef QT_NO_SOUND + static Sound snd ( "keysound" ); + + if ( snd. isFinished()) + snd. play(); +#endif +} + +/** +* This plays a touch sound +*/ +void ODevice::touchSound() +{ +#ifndef QT_NO_SOUND + static Sound snd ( "touchsound" ); + + if ( snd. isFinished()) + snd. play(); +#endif +} + +/** +* This method will return a list of leds +* available on this device +* @return a list of LEDs. +*/ +QValueList <OLed> ODevice::ledList() const +{ + return QValueList <OLed>(); +} + +/** +* This does return the state of the LEDs +*/ +QValueList <OLedState> ODevice::ledStateList ( OLed /*which*/ ) const +{ + return QValueList <OLedState>(); +} + +/** +* @return the state for a given OLed +*/ +OLedState ODevice::ledState ( OLed /*which*/ ) const +{ + return Led_Off; +} + +/** +* Set the state for a LED +* @param which Which OLed to use +* @param st The state to set +* @return success or failure +*/ +bool ODevice::setLedState ( OLed which, OLedState st ) +{ + Q_UNUSED( which ) + Q_UNUSED( st ) + return false; +} + +/** +* @return if the device has a light sensor +*/ +bool ODevice::hasLightSensor() const +{ + return false; +} + +/** +* @return a value from the light sensor +*/ +int ODevice::readLightSensor() +{ + return -1; +} + +/** +* @return the light sensor resolution +*/ +int ODevice::lightSensorResolution() const +{ + return 0; +} + +/** +* @return if the device has a hinge sensor +*/ +bool ODevice::hasHingeSensor() const +{ + return false; +} + +/** +* @return a value from the hinge sensor +*/ +OHingeStatus ODevice::readHingeSensor() +{ + return CASE_UNKNOWN; +} + +/** +* @return a list with CPU frequencies supported by the hardware +*/ +const QStrList &ODevice::allowedCpuFrequencies() const +{ + return *d->m_cpu_frequencies; +} + + +/** +* Set desired CPU frequency +* +* @param index index into d->m_cpu_frequencies of the frequency to be set +*/ +bool ODevice::setCurrentCpuFrequency(uint index) +{ + if (index >= d->m_cpu_frequencies->count()) + return false; + + char *freq = d->m_cpu_frequencies->at(index); + qWarning("set freq to %s", freq); + + int fd; + + if ((fd = ::open("/proc/sys/cpu/0/speed", O_WRONLY)) >= 0) { + char writeCommand[50]; + const int count = sprintf(writeCommand, "%s\n", freq); + int res = (::write(fd, writeCommand, count) != -1); + ::close(fd); + return res; + } + + return false; +} + + +/** +* @return a list of hardware buttons +*/ +const QValueList <ODeviceButton> &ODevice::buttons() +{ + initButtons(); + + return *d->m_buttons; +} + +/** +* @return The amount of time that would count as a hold +*/ +uint ODevice::buttonHoldTime() const +{ + return d->m_holdtime; +} + +/** +* This method return a ODeviceButton for a key code +* or 0 if no special hardware button is available for the device +* +* @return The devicebutton or 0l +* @see ODeviceButton +*/ +const ODeviceButton *ODevice::buttonForKeycode ( ushort code ) +{ + initButtons(); + + for ( QValueListConstIterator<ODeviceButton> it = d->m_buttons->begin(); it != d->m_buttons->end(); ++it ) { + if ( (*it). keycode() == code ) + return &(*it); + } + return 0; +} + +void ODevice::reloadButtonMapping() +{ + initButtons(); + + Config cfg ( "ButtonSettings" ); + + for ( uint i = 0; i < d->m_buttons->count(); i++ ) { + ODeviceButton &b = ( *d->m_buttons ) [i]; + QString group = "Button" + QString::number ( i ); + + QCString pch, hch; + QCString pm, hm; + QByteArray pdata, hdata; + + if ( cfg. hasGroup ( group )) { + cfg. setGroup ( group ); + pch = cfg. readEntry ( "PressedActionChannel" ). latin1(); + pm = cfg. readEntry ( "PressedActionMessage" ). latin1(); + // pdata = decodeBase64 ( buttonFile. readEntry ( "PressedActionArgs" )); + + hch = cfg. readEntry ( "HeldActionChannel" ). latin1(); + hm = cfg. readEntry ( "HeldActionMessage" ). latin1(); + // hdata = decodeBase64 ( buttonFile. readEntry ( "HeldActionArgs" )); + } + + b. setPressedAction ( OQCopMessage ( pch, pm, pdata )); + + b. setHeldAction ( OQCopMessage ( hch, hm, hdata )); + } +} + +void ODevice::remapPressedAction ( int button, const OQCopMessage &action ) +{ + initButtons(); + + QString mb_chan; + + if ( button >= (int) d->m_buttons->count()) + return; + + ODeviceButton &b = ( *d->m_buttons ) [button]; + b. setPressedAction ( action ); + + mb_chan=b. pressedAction(). channel(); + + Config buttonFile ( "ButtonSettings" ); + buttonFile. setGroup ( "Button" + QString::number ( button )); + buttonFile. writeEntry ( "PressedActionChannel", (const char*) mb_chan); + buttonFile. writeEntry ( "PressedActionMessage", (const char*) b. pressedAction(). message()); + +// buttonFile. writeEntry ( "PressedActionArgs", encodeBase64 ( b. pressedAction(). data())); + + QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" ); +} + +void ODevice::remapHeldAction ( int button, const OQCopMessage &action ) +{ + initButtons(); + + if ( button >= (int) d->m_buttons->count()) + return; + + ODeviceButton &b = ( *d->m_buttons ) [button]; + b. setHeldAction ( action ); + + Config buttonFile ( "ButtonSettings" ); + buttonFile. setGroup ( "Button" + QString::number ( button )); + buttonFile. writeEntry ( "HeldActionChannel", (const char *) b. heldAction(). channel()); + buttonFile. writeEntry ( "HeldActionMessage", (const char *) b. heldAction(). message()); + +// buttonFile. writeEntry ( "HeldActionArgs", decodeBase64 ( b. heldAction(). data())); + + QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" ); +} +void ODevice::virtual_hook(int, void* ){ + +} diff --git a/libopie2/opiecore/device/odevice.h b/libopie2/opiecore/device/odevice.h new file mode 100644 index 0000000..bde6411 --- a/dev/null +++ b/libopie2/opiecore/device/odevice.h @@ -0,0 +1,329 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef ODEVICE_H_ +#define ODEVICE_H_ + +#include <opie2/odevicebutton.h> + +/* QT */ +#include <qnamespace.h> +#include <qobject.h> +#include <qstring.h> +#include <qstrlist.h> + +#include <qpe/qpeapplication.h> /* for Transformation enum.. */ + +namespace Opie +{ + class ODeviceData; +/** + * The available devices + */ +enum OModel { + Model_Unknown, // = 0 + + Model_Series_Mask = 0xff000000, + + Model_iPAQ = ( 1 << 24 ), + + Model_iPAQ_All = ( Model_iPAQ | 0xffffff ), + Model_iPAQ_H31xx = ( Model_iPAQ | 0x000001 ), + Model_iPAQ_H36xx = ( Model_iPAQ | 0x000002 ), + Model_iPAQ_H37xx = ( Model_iPAQ | 0x000004 ), + Model_iPAQ_H38xx = ( Model_iPAQ | 0x000008 ), + Model_iPAQ_H39xx = ( Model_iPAQ | 0x000010 ), + Model_iPAQ_H5xxx = ( Model_iPAQ | 0x000011 ), + + Model_Jornada = ( 6 << 24 ), + Model_Jornada_56x = ( Model_Jornada | 0x000001 ), + + Model_Zaurus = ( 2 << 24 ), + + Model_Zaurus_SL5000 = ( Model_Zaurus | 0x000001 ), + Model_Zaurus_SL5500 = ( Model_Zaurus | 0x000002 ), + Model_Zaurus_SLA300 = ( Model_Zaurus | 0x000003 ), + Model_Zaurus_SLB600 = ( Model_Zaurus | 0x000004 ), + Model_Zaurus_SLC7x0 = ( Model_Zaurus | 0x000005 ), + + Model_SIMpad = ( 3 << 24 ), + + Model_SIMpad_All = ( Model_SIMpad | 0xffffff ), + Model_SIMpad_CL4 = ( Model_SIMpad | 0x000001 ), + Model_SIMpad_SL4 = ( Model_SIMpad | 0x000002 ), + Model_SIMpad_SLC = ( Model_SIMpad | 0x000004 ), + Model_SIMpad_TSinus = ( Model_SIMpad | 0x000008 ), + + Model_Ramses = ( 4 << 24 ), + + Model_Ramses_All = ( Model_Ramses | 0xffffff ), + Model_Ramses_MNCI = ( Model_Ramses | 0x000001 ), + + Model_Yopy = ( 5 << 24 ), + + Model_Yopy_All = ( Model_Yopy | 0xffffff ), + Model_Yopy_3000 = ( Model_Yopy | 0x000001 ), + Model_Yopy_3500 = ( Model_Yopy | 0x000002 ), + Model_Yopy_3700 = ( Model_Yopy | 0x000003 ), + +}; + +/** + * The vendor of the device + */ +enum OVendor { + Vendor_Unknown, + + Vendor_HP, + Vendor_Sharp, + Vendor_SIEMENS, + Vendor_MundN, + Vendor_GMate, +}; + +/** + * The System used + */ +enum OSystem { + System_Unknown, + + System_Familiar, + System_Zaurus, + System_OpenZaurus, + System_Linupy, +}; + +enum OLedState { + Led_Off, + Led_On, + Led_BlinkSlow, + Led_BlinkFast +}; + +enum OLed { + Led_Mail, + Led_Power, + Led_BlueTooth +}; + +enum OHardKey { + HardKey_Datebook = Qt::Key_F9, + HardKey_Contacts = Qt::Key_F10, + HardKey_Menu = Qt::Key_F11, + HardKey_Home = Qt::Key_F12, + HardKey_Mail = Qt::Key_F13, + HardKey_Record = Qt::Key_F24, + HardKey_Suspend = Qt::Key_F34, + HardKey_Backlight = Qt::Key_F35, + HardKey_Action = Qt::Key_F10, + HardKey_OK = Qt::Key_F11, + HardKey_End = Qt::Key_F12, +}; + +enum ODirection { + CW = 0, + CCW = 1, + Flip = 2, +}; + +enum OHingeStatus { + CASE_CLOSED = 3, + CASE_PORTRAIT = 2, + CASE_LANDSCAPE = 0, + CASE_UNKNOWN = 1, +}; + +/** + * A singleton which gives informations about device specefic option + * like the Hardware used, LEDs, the Base Distribution and + * hardware key mappings. + * + * @short A small class for device specefic options + * @see QObject + * @author Robert Griebl + * @version 1.0 + */ +class ODevice : public QObject +{ + Q_OBJECT + +private: + /* disable copy */ + ODevice ( const ODevice & ); + +protected: + ODevice(); + virtual void init(); + virtual void initButtons(); + + ODeviceData *d; + +public: + // sandman do we want to allow destructions? -zecke? + virtual ~ODevice(); + + static ODevice *inst(); + + // information + + QString modelString() const; + OModel model() const; + inline OModel series() const { return (OModel) ( model() & Model_Series_Mask ); } + + QString vendorString() const; + OVendor vendor() const; + + QString systemString() const; + OSystem system() const; + + QString systemVersionString() const; + + virtual Transformation rotation() const; + virtual ODirection direction() const; + + // system + + virtual bool setSoftSuspend ( bool on ); + virtual bool suspend(); + + virtual bool setDisplayStatus ( bool on ); + virtual bool setDisplayBrightness ( int brightness ); + virtual int displayBrightnessResolution() const; + virtual bool setDisplayContrast ( int contrast ); + virtual int displayContrastResolution() const; + + // don't add new virtual methods, use this: + // /*virtual */ void boo(int i ) { return virtual_hook(1,&i); }; + // and in your subclass do do overwrite + // protected virtual int virtual_hook(int, void *) + // which is defined below + + // input / output + //FIXME playAlarmSound and al might be better -zecke + virtual void alarmSound(); + virtual void keySound(); + virtual void touchSound(); + + virtual QValueList <OLed> ledList() const; + virtual QValueList <OLedState> ledStateList ( OLed led ) const; + virtual OLedState ledState ( OLed led ) const; + virtual bool setLedState ( OLed led, OLedState st ); + + virtual bool hasLightSensor() const; + virtual int readLightSensor(); + virtual int lightSensorResolution() const; + + virtual bool hasHingeSensor() const; + virtual OHingeStatus readHingeSensor(); + + const QStrList &allowedCpuFrequencies() const; + bool setCurrentCpuFrequency(uint index); + + /** + * Returns the available buttons on this device. The number and location + * of buttons will vary depending on the device. Button numbers will be assigned + * by the device manufacturer and will be from most preferred button to least preffered + * button. Note that this list only contains "user mappable" buttons. + */ + const QValueList<ODeviceButton> &buttons() /* ### make const */; + + /** + * Returns the DeviceButton for the \a keyCode. If \a keyCode is not found, it + * returns 0L + */ + const ODeviceButton *buttonForKeycode ( ushort keyCode ); + + /** + * Reassigns the pressed action for \a button. To return to the factory + * default pass an empty string as \a qcopMessage. + */ + void remapPressedAction ( int button, const OQCopMessage &qcopMessage ); + + /** + * Reassigns the held action for \a button. To return to the factory + * default pass an empty string as \a qcopMessage. + */ + void remapHeldAction ( int button, const OQCopMessage &qcopMessage ); + + /** + * How long (in ms) you have to press a button for a "hold" action + */ + uint buttonHoldTime() const; + +signals: + void buttonMappingChanged(); + +private slots: + void systemMessage ( const QCString &, const QByteArray & ); + +protected: + void reloadButtonMapping(); + /* ugly virtual hook */ + virtual void virtual_hook( int id, void* data ); +}; + +class ODeviceData { + + public: + QString m_vendorstr; + OVendor m_vendor; + + QString m_modelstr; + OModel m_model; + + QString m_systemstr; + OSystem m_system; + + QString m_sysverstr; + + Transformation m_rotation; + ODirection m_direction; + + QValueList <ODeviceButton> *m_buttons; + uint m_holdtime; + QStrList *m_cpu_frequencies; +}; + +} + +static inline bool isQWS() +{ + return qApp ? ( qApp->type() == QApplication::GuiServer ) : false; +} + +static QCString makeChannel ( const char *str ) +{ + if ( str && !::strchr ( str, '/' )) + return QCString ( "QPE/Application/" ) + str; + else + return str; +} + +#endif + diff --git a/libopie2/opiecore/device/odevice_ipaq.cpp b/libopie2/opiecore/device/odevice_ipaq.cpp new file mode 100644 index 0000000..d928806 --- a/dev/null +++ b/libopie2/opiecore/device/odevice_ipaq.cpp @@ -0,0 +1,524 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "odevice.h" + +/* QT */ +#include <qapplication.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qwindowsystem_qws.h> + +/* OPIE */ +#include <qpe/config.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> + +/* STD */ +#include <fcntl.h> +#include <math.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +typedef struct { + unsigned char OffOnBlink; /* 0=off 1=on 2=Blink */ + unsigned char TotalTime; /* Units of 5 seconds */ + unsigned char OnTime; /* units of 100m/s */ + unsigned char OffTime; /* units of 100m/s */ +} LED_IN; + +typedef struct { + unsigned char mode; + unsigned char pwr; + unsigned char brightness; +} FLITE_IN; + +#define LED_ON OD_IOW( 'f', 5, LED_IN ) +#define FLITE_ON OD_IOW( 'f', 7, FLITE_IN ) + +using namespace Opie; + +class iPAQ : public ODevice, public QWSServer::KeyboardFilter +{ + + protected: + virtual void init(); + virtual void initButtons(); + + public: + virtual bool setSoftSuspend( bool soft ); + + virtual bool setDisplayBrightness( int b ); + virtual int displayBrightnessResolution() const; + + virtual void alarmSound(); + + virtual QValueList <OLed> ledList() const; + virtual QValueList <OLedState> ledStateList( OLed led ) const; + virtual OLedState ledState( OLed led ) const; + virtual bool setLedState( OLed led, OLedState st ); + + virtual bool hasLightSensor() const; + virtual int readLightSensor(); + virtual int lightSensorResolution() const; + + protected: + virtual bool filter( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); + virtual void timerEvent( QTimerEvent *te ); + + int m_power_timer; + + OLedState m_leds [2]; +}; + +struct i_button { + uint model; + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} ipaq_buttons [] = { + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), + "devicebuttons/ipaq_calendar", + "datebook", "nextView()", + "today", "raise()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), + "devicebuttons/ipaq_contact", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx, + Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), + "devicebuttons/ipaq_menu", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), + "devicebuttons/ipaq_mail", + "mail", "raise()", + "mail", "newMail()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), + "devicebuttons/ipaq_home", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, + Qt::Key_F24, QT_TRANSLATE_NOOP("Button", "Record Button"), + "devicebuttons/ipaq_record", + "QPE/VMemo", "toggleRecord()", + "sound", "raise()" }, +}; + +void iPAQ::init() +{ + d->m_vendorstr = "HP"; + d->m_vendor = Vendor_HP; + + QFile f ( "/proc/hal/model" ); + + if ( f. open ( IO_ReadOnly )) { + QTextStream ts ( &f ); + + d->m_modelstr = "H" + ts. readLine(); + + if ( d->m_modelstr == "H3100" ) + d->m_model = Model_iPAQ_H31xx; + else if ( d->m_modelstr == "H3600" ) + d->m_model = Model_iPAQ_H36xx; + else if ( d->m_modelstr == "H3700" ) + d->m_model = Model_iPAQ_H37xx; + else if ( d->m_modelstr == "H3800" ) + d->m_model = Model_iPAQ_H38xx; + else if ( d->m_modelstr == "H3900" ) + d->m_model = Model_iPAQ_H39xx; + else if ( d->m_modelstr == "H5400" ) + d->m_model = Model_iPAQ_H5xxx; + else + d->m_model = Model_Unknown; + + f. close(); + } + + switch ( d->m_model ) { + case Model_iPAQ_H31xx: + case Model_iPAQ_H38xx: + d->m_rotation = Rot90; + break; + case Model_iPAQ_H36xx: + case Model_iPAQ_H37xx: + case Model_iPAQ_H39xx: + + default: + d->m_rotation = Rot270; + break; + case Model_iPAQ_H5xxx: + d->m_rotation = Rot0; + } + + f. setName ( "/etc/familiar-version" ); + if ( f. open ( IO_ReadOnly )) { + d->m_systemstr = "Familiar"; + d->m_system = System_Familiar; + + QTextStream ts ( &f ); + d->m_sysverstr = ts. readLine(). mid ( 10 ); + + f. close(); + } else { + f. setName ( "/etc/oz_version" ); + + if ( f. open ( IO_ReadOnly )) { + d->m_systemstr = "OpenEmbedded/iPaq"; + d->m_system = System_Familiar; + + QTextStream ts ( &f ); + ts.setDevice ( &f ); + d->m_sysverstr = ts. readLine(); + f. close(); + } + } + + m_leds [0] = m_leds [1] = Led_Off; + + m_power_timer = 0; + +} + +void iPAQ::initButtons() +{ + if ( d->m_buttons ) + return; + + if ( isQWS( ) ) + QWSServer::setKeyboardFilter ( this ); + + d->m_buttons = new QValueList <ODeviceButton>; + + for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) { + i_button *ib = ipaq_buttons + i; + ODeviceButton b; + + if (( ib->model & d->m_model ) == d->m_model ) { + b. setKeycode ( ib->code ); + b. setUserText ( QObject::tr ( "Button", ib->utext )); + b. setPixmap ( Resource::loadPixmap ( ib->pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib->fpressedservice ), ib->fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib->fheldservice ), ib->fheldaction )); + + d->m_buttons->append ( b ); + } + } + reloadButtonMapping(); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); +} + +QValueList <OLed> iPAQ::ledList() const +{ + QValueList <OLed> vl; + vl << Led_Power; + + if ( d->m_model == Model_iPAQ_H38xx ) + vl << Led_BlueTooth; + return vl; +} + +QValueList <OLedState> iPAQ::ledStateList ( OLed l ) const +{ + QValueList <OLedState> vl; + + if ( l == Led_Power ) + vl << Led_Off << Led_On << Led_BlinkSlow << Led_BlinkFast; + else if ( l == Led_BlueTooth && d->m_model == Model_iPAQ_H38xx ) + vl << Led_Off; // << Led_On << ??? + + return vl; +} + +OLedState iPAQ::ledState ( OLed l ) const +{ + switch ( l ) { + case Led_Power: + return m_leds [0]; + case Led_BlueTooth: + return m_leds [1]; + default: + return Led_Off; + } +} + +bool iPAQ::setLedState ( OLed l, OLedState st ) +{ + static int fd = ::open ( "/dev/touchscreen/0", O_RDWR | O_NONBLOCK ); + + if ( l == Led_Power ) { + if ( fd >= 0 ) { + LED_IN leds; + ::memset ( &leds, 0, sizeof( leds )); + leds. TotalTime = 0; + leds. OnTime = 0; + leds. OffTime = 1; + leds. OffOnBlink = 2; + + switch ( st ) { + case Led_Off : leds. OffOnBlink = 0; break; + case Led_On : leds. OffOnBlink = 1; break; + case Led_BlinkSlow: leds. OnTime = 10; leds. OffTime = 10; break; + case Led_BlinkFast: leds. OnTime = 5; leds. OffTime = 5; break; + } + + if ( ::ioctl ( fd, LED_ON, &leds ) >= 0 ) { + m_leds [0] = st; + return true; + } + } + } + return false; +} + + +bool iPAQ::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat ) +{ + int newkeycode = keycode; + + switch ( keycode ) { + // H38xx/H39xx have no "Q" key anymore - this is now the Mail key + case HardKey_Menu: { + if (( d->m_model == Model_iPAQ_H38xx ) || + ( d->m_model == Model_iPAQ_H39xx ) || + ( d->m_model == Model_iPAQ_H5xxx)) { + newkeycode = HardKey_Mail; + } + break; + } + + // Rotate cursor keys 180° + case Key_Left : + case Key_Right: + case Key_Up : + case Key_Down : { + if (( d->m_model == Model_iPAQ_H31xx ) || + ( d->m_model == Model_iPAQ_H38xx )) { + newkeycode = Key_Left + ( keycode - Key_Left + 2 ) % 4; + } + break; + } + + // map Power Button short/long press to F34/F35 + case Key_SysReq: { + if ( isPress ) { + if ( m_power_timer ) + killTimer ( m_power_timer ); + m_power_timer = startTimer ( 500 ); + } + else if ( m_power_timer ) { + killTimer ( m_power_timer ); + m_power_timer = 0; + QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, true, false ); + QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, false, false ); + } + newkeycode = Key_unknown; + break; + } + } + + if ( newkeycode != keycode ) { + if ( newkeycode != Key_unknown ) + QWSServer::sendKeyEvent ( -1, newkeycode, modifiers, isPress, autoRepeat ); + return true; + } + else + return false; +} + +void iPAQ::timerEvent ( QTimerEvent * ) +{ + killTimer ( m_power_timer ); + m_power_timer = 0; + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false ); + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false ); +} + + +void iPAQ::alarmSound() +{ +#ifndef QT_NO_SOUND + static Sound snd ( "alarm" ); + int fd; + int vol; + bool vol_reset = false; + + if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { + if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { + Config cfg ( "qpe" ); + cfg. setGroup ( "Volume" ); + + int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); + if ( volalarm < 0 ) + volalarm = 0; + else if ( volalarm > 100 ) + volalarm = 100; + volalarm |= ( volalarm << 8 ); + + if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) + vol_reset = true; + } + } + + snd. play(); + while ( !snd. isFinished()) + qApp->processEvents(); + + if ( fd >= 0 ) { + if ( vol_reset ) + ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); + ::close ( fd ); + } +#endif +} + + +bool iPAQ::setSoftSuspend ( bool soft ) +{ + bool res = false; + int fd; + + if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) { + if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 ) + res = true; + else + ::perror ( "write to /proc/sys/ts/suspend_button_mode" ); + + ::close ( fd ); + } + else + ::perror ( "/proc/sys/ts/suspend_button_mode" ); + + return res; +} + + +bool iPAQ::setDisplayBrightness ( int bright ) +{ + bool res = false; + int fd; + + if ( bright > 255 ) + bright = 255; + if ( bright < 0 ) + bright = 0; + + if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) { + FLITE_IN bl; + bl. mode = 1; + bl. pwr = bright ? 1 : 0; + bl. brightness = ( bright * ( displayBrightnessResolution() - 1 ) + 127 ) / 255; + res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 ); + ::close ( fd ); + } + return res; +} + +int iPAQ::displayBrightnessResolution() const +{ + switch ( model()) { + case Model_iPAQ_H31xx: + case Model_iPAQ_H36xx: + case Model_iPAQ_H37xx: + return 128; // really 256, but >128 could damage the LCD + + case Model_iPAQ_H38xx: + case Model_iPAQ_H39xx: + return 64; + case Model_iPAQ_H5xxx: + return 255; + + default: + return 2; + } +} + + +bool iPAQ::hasLightSensor() const +{ + return true; +} + +int iPAQ::readLightSensor() +{ + int fd; + int val = -1; + + if (( fd = ::open ( "/proc/hal/light_sensor", O_RDONLY )) >= 0 ) { + char buffer [8]; + + if ( ::read ( fd, buffer, 5 ) == 5 ) { + char *endptr; + + buffer [4] = 0; + val = ::strtol ( buffer + 2, &endptr, 16 ); + + if ( *endptr != 0 ) + val = -1; + } + ::close ( fd ); + } + + return val; +} + +int iPAQ::lightSensorResolution() const +{ + return 256; +} diff --git a/libopie2/opiecore/device/odevice_jornada.cpp b/libopie2/opiecore/device/odevice_jornada.cpp new file mode 100644 index 0000000..bcd03ed --- a/dev/null +++ b/libopie2/opiecore/device/odevice_jornada.cpp @@ -0,0 +1,214 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "odevice.h" + +/* QT */ +#include <qapplication.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qwindowsystem_qws.h> + +/* OPIE */ +#include <qpe/config.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> + +/* STD */ +#include <fcntl.h> +#include <math.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +typedef struct { + unsigned char OffOnBlink; /* 0=off 1=on 2=Blink */ + unsigned char TotalTime; /* Units of 5 seconds */ + unsigned char OnTime; /* units of 100m/s */ + unsigned char OffTime; /* units of 100m/s */ +} LED_IN; + +typedef struct { + unsigned char mode; + unsigned char pwr; + unsigned char brightness; +} FLITE_IN; + +#define LED_ON OD_IOW( 'f', 5, LED_IN ) +#define FLITE_ON OD_IOW( 'f', 7, FLITE_IN ) + +using namespace Opie; + +class Jornada : public ODevice +{ + + protected: + virtual void init(); + + public: + virtual bool setSoftSuspend ( bool soft ); + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution() const; + static bool isJornada(); +}; + + +bool Jornada::isJornada() +{ + QFile f( "/proc/cpuinfo" ); + if ( f. open ( IO_ReadOnly ) ) { + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine() ) { + if ( line. left ( 8 ) == "Hardware" ) { + int loc = line. find ( ":" ); + if ( loc != -1 ) { + QString model = line.mid( loc + 2 ).simplifyWhiteSpace( ); + return ( model == "HP Jornada 56x" ); + } + } + } + } + return false; +} + +void Jornada::init() +{ + d->m_vendorstr = "HP"; + d->m_vendor = Vendor_HP; + d->m_modelstr = "Jornada 56x"; + d->m_model = Model_Jornada_56x; + d->m_systemstr = "Familiar"; + d->m_system = System_Familiar; + d->m_rotation = Rot0; + + QFile f ( "/etc/familiar-version" ); + f. setName ( "/etc/familiar-version" ); + if ( f. open ( IO_ReadOnly )) { + + QTextStream ts ( &f ); + d->m_sysverstr = ts. readLine(). mid ( 10 ); + + f. close(); + } +} + +#if 0 +void Jornada::initButtons() +{ + if ( d->m_buttons ) + return; + + // Simulation uses iPAQ 3660 device buttons + + qDebug ( "init Buttons" ); + d->m_buttons = new QValueList <ODeviceButton>; + + for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) { + i_button *ib = ipaq_buttons + i; + ODeviceButton b; + + if (( ib->model & Model_iPAQ_H36xx ) == Model_iPAQ_H36xx ) { + b. setKeycode ( ib->code ); + b. setUserText ( QObject::tr ( "Button", ib->utext )); + b. setPixmap ( Resource::loadPixmap ( ib->pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib->fpressedservice ), ib->fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib->fheldservice ), ib->fheldaction )); + d->m_buttons->append ( b ); + } + } + reloadButtonMapping(); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); +} +#endif + +int Jornada::displayBrightnessResolution() const +{ +} + +bool Jornada::setDisplayBrightness( int bright ) +{ + bool res = false; + int fd; + + if ( bright > 255 ) + bright = 255; + if ( bright < 0 ) + bright = 0; + + if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) { + FLITE_IN bl; + bl. mode = 1; + bl. pwr = bright ? 1 : 0; + bl. brightness = ( bright * ( displayBrightnessResolution() - 1 ) + 127 ) / 255; + res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 ); + ::close ( fd ); + } + return res; +} + +bool Jornada::setSoftSuspend( bool soft ) +{ + bool res = false; + int fd; + + if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) { + if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 ) + res = true; + else + ::perror ( "write to /proc/sys/ts/suspend_button_mode" ); + + ::close ( fd ); + } + else + ::perror ( "/proc/sys/ts/suspend_button_mode" ); + + return res; +} diff --git a/libopie2/opiecore/device/odevice_ramses.cpp b/libopie2/opiecore/device/odevice_ramses.cpp new file mode 100644 index 0000000..a90c3a0 --- a/dev/null +++ b/libopie2/opiecore/device/odevice_ramses.cpp @@ -0,0 +1,317 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "odevice.h" + +/* QT */ +#include <qapplication.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qwindowsystem_qws.h> + +/* OPIE */ +#include <qpe/config.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> + +/* STD */ +#include <fcntl.h> +#include <math.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +using namespace Opie; + +class Ramses : public ODevice, public QWSServer::KeyboardFilter +{ + protected: + virtual void init(); + + public: + virtual bool setSoftSuspend( bool soft ); + virtual bool suspend(); + + virtual bool setDisplayStatus( bool on ); + virtual bool setDisplayBrightness( int b ); + virtual int displayBrightnessResolution() const; + virtual bool setDisplayContrast( int b ); + virtual int displayContrastResolution() const; + + protected: + virtual bool filter ( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); + virtual void timerEvent ( QTimerEvent *te ); + + int m_power_timer; +}; + +struct r_button { + uint model; + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} ramses_buttons [] = { + { Model_Ramses_MNCI, + Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), + "devicebuttons/z_menu", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Model_Ramses_MNCI, + Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), + "devicebuttons/ipaq_home", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, +}; + +void Ramses::init() +{ + d->m_vendorstr = "M und N"; + d->m_vendor = Vendor_MundN; + + QFile f("/proc/sys/board/ramses"); + + d->m_modelstr = "Ramses"; + d->m_model = Model_Ramses_MNCI; + + d->m_rotation = Rot0; + d->m_holdtime = 1000; + + f.setName("/etc/oz_version"); + + if (f.open(IO_ReadOnly)) { + d->m_systemstr = "OpenEmbedded/Ramses"; + d->m_system = System_OpenZaurus; + + QTextStream ts(&f); + ts.setDevice(&f); + d->m_sysverstr = ts.readLine(); + f.close(); + } + + m_power_timer = 0; + +#ifdef QT_QWS_ALLOW_OVERCLOCK +#warning *** Overclocking enabled - this may fry your hardware - you have been warned *** +#define OC(x...) x +#else +#define OC(x...) +#endif + + // This table is true for a Intel XScale PXA 255 + + d->m_cpu_frequencies->append("99000"); // mem= 99, run= 99, turbo= 99, PXbus= 50 +OC(d->m_cpu_frequencies->append("118000"); ) // mem=118, run=118, turbo=118, PXbus= 59 OC'd mem + d->m_cpu_frequencies->append("199100"); // mem= 99, run=199, turbo=199, PXbus= 99 +OC(d->m_cpu_frequencies->append("236000"); ) // mem=118, run=236, turbo=236, PXbus=118 OC'd mem + d->m_cpu_frequencies->append("298600"); // mem= 99, run=199, turbo=298, PXbus= 99 +OC(d->m_cpu_frequencies->append("354000"); ) // mem=118, run=236, turbo=354, PXbus=118 OC'd mem + d->m_cpu_frequencies->append("398099"); // mem= 99, run=199, turbo=398, PXbus= 99 + d->m_cpu_frequencies->append("398100"); // mem= 99, run=398, turbo=398, PXbus=196 +OC(d->m_cpu_frequencies->append("471000"); ) // mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus + +} + +bool Ramses::filter(int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat) +{ + Q_UNUSED( keycode ); + Q_UNUSED( modifiers ); + Q_UNUSED( isPress ); + Q_UNUSED( autoRepeat ); + return false; +} + +void Ramses::timerEvent(QTimerEvent *) +{ + killTimer(m_power_timer); + m_power_timer = 0; + QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, true, false); + QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, false, false); +} + + +bool Ramses::setSoftSuspend(bool soft) +{ + qDebug("Ramses::setSoftSuspend(%d)", soft); +#if 0 + bool res = false; + int fd; + + if (((fd = ::open("/dev/apm_bios", O_RDWR)) >= 0) || + ((fd = ::open("/dev/misc/apm_bios",O_RDWR)) >= 0)) { + + int sources = ::ioctl(fd, APM_IOCGEVTSRC, 0); // get current event sources + + if (sources >= 0) { + if (soft) + sources &= ~APM_EVT_POWER_BUTTON; + else + sources |= APM_EVT_POWER_BUTTON; + + if (::ioctl(fd, APM_IOCSEVTSRC, sources) >= 0) // set new event sources + res = true; + else + perror("APM_IOCGEVTSRC"); + } + else + perror("APM_IOCGEVTSRC"); + + ::close(fd); + } + else + perror("/dev/apm_bios or /dev/misc/apm_bios"); + + return res; +#else + return true; +#endif +} + +bool Ramses::suspend() +{ + qDebug("Ramses::suspend"); + return false; +} + +/** +* This sets the display on or off +*/ +bool Ramses::setDisplayStatus(bool on) +{ + qDebug("Ramses::setDisplayStatus(%d)", on); +#if 0 + bool res = false; + int fd; + + if ((fd = ::open ("/dev/fb/0", O_RDWR)) >= 0) { + res = (::ioctl(fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN) == 0); + ::close(fd); + } + return res; +#else + return true; +#endif +} + + +/* +* We get something between 0..255 into us +*/ +bool Ramses::setDisplayBrightness(int bright) +{ + qDebug("Ramses::setDisplayBrightness(%d)", bright); + bool res = false; + int fd; + + // pwm1 brighness: 20 steps 500..0 (dunkel->hell) + + if (bright > 255 ) + bright = 255; + if (bright < 0) + bright = 0; + + // Turn backlight completely off + if ((fd = ::open("/proc/sys/board/lcd_backlight", O_WRONLY)) >= 0) { + char writeCommand[10]; + const int count = sprintf(writeCommand, "%d\n", bright ? 1 : 0); + res = (::write(fd, writeCommand, count) != -1); + ::close(fd); + } + + // scale backlight brightness to hardware + bright = 500-(bright * 500 / 255); + if ((fd = ::open("/proc/sys/board/pwm1", O_WRONLY)) >= 0) { + qDebug(" %d ->pwm1", bright); + char writeCommand[100]; + const int count = sprintf(writeCommand, "%d\n", bright); + res = (::write(fd, writeCommand, count) != -1); + ::close(fd); + } + return res; +} + + +int Ramses::displayBrightnessResolution() const +{ + return 32; +} + +bool Ramses::setDisplayContrast(int contr) +{ + qDebug("Ramses::setDisplayContrast(%d)", contr); + bool res = false; + int fd; + + // pwm0 contrast: 20 steps 79..90 (dunkel->hell) + + if (contr > 255 ) + contr = 255; + if (contr < 0) + contr = 0; + contr = 90 - (contr * 20 / 255); + + if ((fd = ::open("/proc/sys/board/pwm0", O_WRONLY)) >= 0) { + qDebug(" %d ->pwm0", contr); + char writeCommand[100]; + const int count = sprintf(writeCommand, "%d\n", contr); + res = (::write(fd, writeCommand, count) != -1); + res = true; + ::close(fd); + } + return res; +} + + +int Ramses::displayContrastResolution() const +{ + return 20; +} + diff --git a/libopie2/opiecore/device/odevice_simpad.cpp b/libopie2/opiecore/device/odevice_simpad.cpp new file mode 100644 index 0000000..82dce10 --- a/dev/null +++ b/libopie2/opiecore/device/odevice_simpad.cpp @@ -0,0 +1,443 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "odevice.h" + +/* QT */ +#include <qapplication.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qwindowsystem_qws.h> + +/* OPIE */ +#include <qpe/config.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> + +/* STD */ +#include <fcntl.h> +#include <math.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +using namespace Opie; + +class SIMpad : public ODevice, public QWSServer::KeyboardFilter +{ + protected: + virtual void init(); + virtual void initButtons(); + + public: + virtual bool setSoftSuspend( bool soft ); + virtual bool suspend(); + + virtual bool setDisplayStatus( bool on ); + virtual bool setDisplayBrightness( int b ); + virtual int displayBrightnessResolution() const; + + virtual void alarmSound(); + + virtual QValueList <OLed> ledList() const; + virtual QValueList <OLedState> ledStateList( OLed led ) const; + virtual OLedState ledState( OLed led ) const; + virtual bool setLedState( OLed led, OLedState st ); + + protected: + virtual bool filter( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); + virtual void timerEvent( QTimerEvent *te ); + + int m_power_timer; + + OLedState m_leds [1]; +}; + +struct s_button { + uint model; + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} simpad_buttons [] = { + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Lower+Up"), + "devicebuttons/simpad_lower_up", + "datebook", "nextView()", + "today", "raise()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Lower+Down"), + "devicebuttons/simpad_lower_down", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Lower+Right"), + "devicebuttons/simpad_lower_right", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Lower+Left"), + "devicebuttons/simpad_lower_left", + "mail", "raise()", + "mail", "newMail()" }, + + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F5, QT_TRANSLATE_NOOP("Button", "Upper+Up"), + "devicebuttons/simpad_upper_up", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F6, QT_TRANSLATE_NOOP("Button", "Upper+Down"), + "devicebuttons/simpad_upper_down", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F7, QT_TRANSLATE_NOOP("Button", "Upper+Right"), + "devicebuttons/simpad_upper_right", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Upper+Left"), + "devicebuttons/simpad_upper_left", + "QPE/Rotation", "flip()", + "QPE/Rotation", "flip()" }, + /* + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"), + "devicebuttons/simpad_lower_upper", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, + Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"), + "devicebuttons/simpad_upper_lower", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + */ +}; + +void SIMpad::init() +{ + d->m_vendorstr = "SIEMENS"; + d->m_vendor = Vendor_SIEMENS; + + QFile f ( "/proc/hal/model" ); + + //TODO Implement model checking + //FIXME For now we assume an SL4 + + d->m_modelstr = "SL4"; + d->m_model = Model_SIMpad_SL4; + + switch ( d->m_model ) { + default: + d->m_rotation = Rot0; + d->m_direction = CCW; + d->m_holdtime = 1000; // 1000ms + + break; + } + + f. setName ( "/etc/familiar-version" ); + if ( f. open ( IO_ReadOnly )) { + d->m_systemstr = "Familiar"; + d->m_system = System_Familiar; + + QTextStream ts ( &f ); + d->m_sysverstr = ts. readLine(). mid ( 10 ); + + f. close(); + } else { + f. setName ( "/etc/oz_version" ); + + if ( f. open ( IO_ReadOnly )) { + d->m_systemstr = "OpenEmbedded/SIMpad"; + d->m_system = System_OpenZaurus; + + QTextStream ts ( &f ); + ts.setDevice ( &f ); + d->m_sysverstr = ts. readLine(); + f. close(); + } + } + + m_leds [0] = m_leds [1] = Led_Off; + + m_power_timer = 0; + +} + +void SIMpad::initButtons() +{ + if ( d->m_buttons ) + return; + + if ( isQWS( ) ) + QWSServer::setKeyboardFilter ( this ); + + d->m_buttons = new QValueList <ODeviceButton>; + + for ( uint i = 0; i < ( sizeof( simpad_buttons ) / sizeof( s_button )); i++ ) { + s_button *sb = simpad_buttons + i; + ODeviceButton b; + + if (( sb->model & d->m_model ) == d->m_model ) { + b. setKeycode ( sb->code ); + b. setUserText ( QObject::tr ( "Button", sb->utext )); + b. setPixmap ( Resource::loadPixmap ( sb->pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( sb->fpressedservice ), sb->fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( sb->fheldservice ), sb->fheldaction )); + + d->m_buttons->append ( b ); + } + } + reloadButtonMapping(); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); +} + +// SIMpad boardcontrol register CS3 +#define SIMPAD_BOARDCONTROL "/proc/cs3" +#define SIMPAD_VCC_5V_EN 0x0001 // For 5V PCMCIA +#define SIMPAD_VCC_3V_EN 0x0002 // FOR 3.3V PCMCIA +#define SIMPAD_EN1 0x0004 // This is only for EPROM's +#define SIMPAD_EN0 0x0008 // Both should be enable for 3.3V or 5V +#define SIMPAD_DISPLAY_ON 0x0010 +#define SIMPAD_PCMCIA_BUFF_DIS 0x0020 +#define SIMPAD_MQ_RESET 0x0040 +#define SIMPAD_PCMCIA_RESET 0x0080 +#define SIMPAD_DECT_POWER_ON 0x0100 +#define SIMPAD_IRDA_SD 0x0200 // Shutdown for powersave +#define SIMPAD_RS232_ON 0x0400 +#define SIMPAD_SD_MEDIAQ 0x0800 // Shutdown for powersave +#define SIMPAD_LED2_ON 0x1000 +#define SIMPAD_IRDA_MODE 0x2000 // Fast/Slow IrDA mode +#define SIMPAD_ENABLE_5V 0x4000 // Enable 5V circuit +#define SIMPAD_RESET_SIMCARD 0x8000 + +//SIMpad touchscreen backlight strength control +#define SIMPAD_BACKLIGHT_CONTROL "/proc/driver/mq200/registers/PWM_CONTROL" +#define SIMPAD_BACKLIGHT_MASK 0x00a10044 + +QValueList <OLed> SIMpad::ledList() const +{ + QValueList <OLed> vl; + vl << Led_Power; //FIXME which LED is LED2 ? The green one or the amber one? + //vl << Led_Mail; //TODO find out if LED1 is accessible anyway + return vl; +} + +QValueList <OLedState> SIMpad::ledStateList ( OLed l ) const +{ + QValueList <OLedState> vl; + + if ( l == Led_Power ) //FIXME which LED is LED2 ? The green one or the amber one? + vl << Led_Off << Led_On; + //else if ( l == Led_Mail ) //TODO find out if LED1 is accessible anyway + //vl << Led_Off; + return vl; +} + +OLedState SIMpad::ledState ( OLed l ) const +{ + switch ( l ) { + case Led_Power: + return m_leds [0]; + //case Led_Mail: + // return m_leds [1]; + default: + return Led_Off; + } +} + +bool SIMpad::setLedState ( OLed l, OLedState st ) +{ +#if 0 + static int fd = ::open ( SIMPAD_BOARDCONTROL, O_RDWR | O_NONBLOCK ); + + /*TODO Implement this like that: + read from cs3 + && with SIMPAD_LED2_ON + write to cs3 */ + m_leds [0] = st; + return true; + } + } + } + +#endif + return false; +} + + +bool SIMpad::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat ) +{ + //TODO + return false; +} + +void SIMpad::timerEvent ( QTimerEvent * ) +{ + killTimer ( m_power_timer ); + m_power_timer = 0; + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false ); + QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false ); +} + + +void SIMpad::alarmSound() +{ +#ifndef QT_NO_SOUND + static Sound snd ( "alarm" ); + int fd; + int vol; + bool vol_reset = false; + + if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { + if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { + Config cfg ( "qpe" ); + cfg. setGroup ( "Volume" ); + + int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); + if ( volalarm < 0 ) + volalarm = 0; + else if ( volalarm > 100 ) + volalarm = 100; + volalarm |= ( volalarm << 8 ); + + if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) + vol_reset = true; + } + } + + snd. play(); + while ( !snd. isFinished()) + qApp->processEvents(); + + if ( fd >= 0 ) { + if ( vol_reset ) + ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); + ::close ( fd ); + } +#endif +} + + +bool SIMpad::suspend() // Must override because SIMpad does NOT have apm +{ + qDebug( "ODevice for SIMpad: suspend()" ); + if ( !isQWS( ) ) // only qwsserver is allowed to suspend + return false; + + bool res = false; + + struct timeval tvs, tvn; + ::gettimeofday ( &tvs, 0 ); + + ::sync(); // flush fs caches + res = ( ::system ( "cat /dev/fb/0 >/tmp/.buffer; echo > /proc/sys/pm/suspend; cat /tmp/.buffer >/dev/fb/0" ) == 0 ); //TODO make better :) + + return res; +} + + +bool SIMpad::setSoftSuspend ( bool soft ) +{ + qDebug( "ODevice for SIMpad: UNHANDLED setSoftSuspend(%s)", soft? "on" : "off" ); + return false; +} + + +bool SIMpad::setDisplayStatus ( bool on ) +{ + qDebug( "ODevice for SIMpad: setDisplayStatus(%s)", on? "on" : "off" ); + + bool res = false; + int fd; + + QString cmdline = QString().sprintf( "echo %s > /proc/cs3", on ? "0xd41a" : "0xd40a" ); //TODO make better :) + + res = ( ::system( (const char*) cmdline ) == 0 ); + + return res; +} + + +bool SIMpad::setDisplayBrightness ( int bright ) +{ + qDebug( "ODevice for SIMpad: setDisplayBrightness( %d )", bright ); + bool res = false; + int fd; + + if ( bright > 255 ) + bright = 255; + if ( bright < 1 ) + bright = 0; + + if (( fd = ::open ( SIMPAD_BACKLIGHT_CONTROL, O_WRONLY )) >= 0 ) { + int value = 255 - bright; + const int mask = SIMPAD_BACKLIGHT_MASK; + value = value << 8; + value += mask; + char writeCommand[100]; + const int count = sprintf( writeCommand, "0x%x\n", value ); + res = ( ::write ( fd, writeCommand, count ) != -1 ); + ::close ( fd ); + } + return res; +} + + +int SIMpad::displayBrightnessResolution() const +{ + return 255; // All SIMpad models share the same display +} + diff --git a/libopie2/opiecore/device/odevice_yopy.cpp b/libopie2/opiecore/device/odevice_yopy.cpp new file mode 100644 index 0000000..9d0cdeb --- a/dev/null +++ b/libopie2/opiecore/device/odevice_yopy.cpp @@ -0,0 +1,212 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "odevice.h" + +/* QT */ +#include <qapplication.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qwindowsystem_qws.h> + +/* OPIE */ +#include <qpe/config.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> + +/* STD */ +#include <fcntl.h> +#include <math.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +using namespace Opie; + +class Yopy : public ODevice +{ + protected: + + virtual void init(); + virtual void initButtons(); + + public: + virtual bool suspend(); + + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution() const; + + static bool isYopy(); +}; + +struct yopy_button { + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} yopy_buttons [] = { +{ Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Action Button"), + "devicebuttons/yopy_action", + "datebook", "nextView()", + "today", "raise()" }, +{ Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "OK Button"), + "devicebuttons/yopy_ok", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, +{ Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "End Button"), + "devicebuttons/yopy_end", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, +}; + +bool Yopy::isYopy() +{ +QFile f( "/proc/cpuinfo" ); +if ( f. open ( IO_ReadOnly ) ) { + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine() ) { + if ( line. left ( 8 ) == "Hardware" ) { + int loc = line. find ( ":" ); + if ( loc != -1 ) { + QString model = + line. mid ( loc + 2 ). simplifyWhiteSpace( ); + return ( model == "Yopy" ); + } + } + } +} +return false; +} + +void Yopy::init() +{ +d->m_vendorstr = "G.Mate"; +d->m_vendor = Vendor_GMate; +d->m_modelstr = "Yopy3700"; +d->m_model = Model_Yopy_3700; +d->m_rotation = Rot0; + +d->m_systemstr = "Linupy"; +d->m_system = System_Linupy; + +QFile f ( "/etc/issue" ); +if ( f. open ( IO_ReadOnly )) { + QTextStream ts ( &f ); + ts.readLine(); + d->m_sysverstr = ts. readLine(); + f. close(); +} +} + +void Yopy::initButtons() +{ +if ( d->m_buttons ) + return; + +d->m_buttons = new QValueList <ODeviceButton>; + +for (uint i = 0; i < ( sizeof( yopy_buttons ) / sizeof(yopy_button)); i++) { + + yopy_button *ib = yopy_buttons + i; + + ODeviceButton b; + + b. setKeycode ( ib->code ); + b. setUserText ( QObject::tr ( "Button", ib->utext )); + b. setPixmap ( Resource::loadPixmap ( ib->pix )); + b. setFactoryPresetPressedAction + (OQCopMessage(makeChannel(ib->fpressedservice), ib->fpressedaction)); + b. setFactoryPresetHeldAction + (OQCopMessage(makeChannel(ib->fheldservice), ib->fheldaction)); + + d->m_buttons->append ( b ); +} +reloadButtonMapping(); + +QCopChannel *sysch = new QCopChannel("QPE/System", this); +connect(sysch, SIGNAL(received(const QCString &, const QByteArray & )), + this, SLOT(systemMessage(const QCString &, const QByteArray & ))); +} + +bool Yopy::suspend() +{ +/* Opie for Yopy does not implement its own power management at the + moment. The public version runs parallel to X, and relies on the + existing power management features. */ +return false; +} + +bool Yopy::setDisplayBrightness(int bright) +{ +/* The code here works, but is disabled as the current version runs + parallel to X, and relies on the existing backlight demon. */ +#if 0 +if ( QFile::exists("/proc/sys/pm/light") ) { + int fd = ::open("/proc/sys/pm/light", O_WRONLY); + if (fd >= 0 ) { + if (bright) + ::write(fd, "1\n", 2); + else + ::write(fd, "0\n", 2); + ::close(fd); + return true; + } +} +#endif +return false; +} + +int Yopy::displayBrightnessResolution() const +{ + return 2; +} + diff --git a/libopie2/opiecore/device/odevice_zaurus.cpp b/libopie2/opiecore/device/odevice_zaurus.cpp new file mode 100644 index 0000000..a6e8b82 --- a/dev/null +++ b/libopie2/opiecore/device/odevice_zaurus.cpp @@ -0,0 +1,790 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "odevice.h" + +/* QT */ +#include <qapplication.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qwindowsystem_qws.h> + +/* OPIE */ +#include <qpe/config.h> +#include <qpe/resource.h> +#include <qpe/sound.h> +#include <qpe/qcopenvelope_qws.h> + +/* STD */ +#include <fcntl.h> +#include <math.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <unistd.h> +#ifndef QT_NO_SOUND +#include <linux/soundcard.h> +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +// _IO and friends are only defined in kernel headers ... + +#define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) + +#define OD_IO(type,number) OD_IOC(0,type,number,0) +#define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) +#define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) +#define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) + +using namespace Opie; + +class Zaurus : public ODevice +{ + + protected: + virtual void init(); + virtual void initButtons(); + + public: + virtual bool setSoftSuspend ( bool soft ); + + virtual bool setDisplayBrightness ( int b ); + virtual int displayBrightnessResolution() const; + + virtual void alarmSound(); + virtual void keySound(); + virtual void touchSound(); + + virtual QValueList <OLed> ledList() const; + virtual QValueList <OLedState> ledStateList ( OLed led ) const; + virtual OLedState ledState( OLed led ) const; + virtual bool setLedState( OLed led, OLedState st ); + + virtual bool hasHingeSensor() const; + virtual OHingeStatus readHingeSensor(); + + static bool isZaurus(); + + virtual bool suspend(); + virtual Transformation rotation() const; + virtual ODirection direction() const; + + protected: + virtual void buzzer ( int snd ); + + OLedState m_leds [1]; + bool m_embedix; +}; + +struct z_button { + Qt::Key code; + char *utext; + char *pix; + char *fpressedservice; + char *fpressedaction; + char *fheldservice; + char *fheldaction; +} z_buttons [] = { + { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), + "devicebuttons/z_calendar", + "datebook", "nextView()", + "today", "raise()" }, + { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), + "devicebuttons/z_contact", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), + "devicebuttons/z_home", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), + "devicebuttons/z_menu", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), + "devicebuttons/z_mail", + "mail", "raise()", + "mail", "newMail()" }, +}; + +struct z_button z_buttons_c700 [] = { + { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), + "devicebuttons/z_calendar", + "datebook", "nextView()", + "today", "raise()" }, + { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), + "devicebuttons/z_contact", + "addressbook", "raise()", + "addressbook", "beamBusinessCard()" }, + { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), + "devicebuttons/z_home", + "QPE/Launcher", "home()", + "buttonsettings", "raise()" }, + { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), + "devicebuttons/z_menu", + "QPE/TaskBar", "toggleMenu()", + "QPE/TaskBar", "toggleStartMenu()" }, + { Qt::Key_F14, QT_TRANSLATE_NOOP("Button", "Display Rotate"), + "devicebuttons/z_hinge", + "QPE/Rotation", "rotateDefault()", + "QPE/Dummy", "doNothing()" }, +}; + +// Check whether this device is the sharp zaurus.. +// FIXME This gets unnecessary complicated. We should think about splitting the Zaurus +// class up into individual classes. We need three classes +// +// Zaurus-Collie (SA-model w/ 320x240 lcd, for SL5500 and SL5000) +// Zaurus-Poodle (PXA-model w/ 320x240 lcd, for SL5600) +// Zaurus-Corgi (PXA-model w/ 640x480 lcd, for C700, C750, C760, and C860) +// +// Only question right now is: Do we really need to do it? Because as soon +// as the OpenZaurus kernel is ready, there will be a unified interface for all +// Zaurus models (concerning apm, backlight, buttons, etc.) +// +// Comments? - mickeyl. + +bool Zaurus::isZaurus() +{ + + // If the special devices by embedix exist, it is quite simple: it is a Zaurus ! + if ( QFile::exists ( "/dev/sharp_buz" ) || QFile::exists ( "/dev/sharp_led" ) ){ + return true; + } + + // On non-embedix kernels, we have to look closer. + bool is_zaurus = false; + QFile f ( "/proc/cpuinfo" ); + if ( f. open ( IO_ReadOnly ) ) { + QString model; + QFile f ( "/proc/cpuinfo" ); + + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine() ) { + if ( line. left ( 8 ) == "Hardware" ) + break; + } + int loc = line. find ( ":" ); + if ( loc != -1 ) + model = line. mid ( loc + 2 ). simplifyWhiteSpace( ); + + if ( model == "Sharp-Collie" + || model == "Collie" + || model == "SHARP Corgi" + || model == "SHARP Shepherd" + || model == "SHARP Poodle" + || model == "SHARP Husky" + ) + is_zaurus = true; + + } + return is_zaurus; +} + + +void Zaurus::init() +{ + d->m_vendorstr = "Sharp"; + d->m_vendor = Vendor_Sharp; + m_embedix = true; // Not openzaurus means: It has an embedix kernel ! + + // QFile f ( "/proc/filesystems" ); + QString model; + + // It isn't a good idea to check the system configuration to + // detect the distribution ! + // Otherwise it may happen that any other distribution is detected as openzaurus, just + // because it uses a jffs2 filesystem.. + // (eilers) + // if ( f. open ( IO_ReadOnly ) && ( QTextStream ( &f ). read(). find ( "\tjffs2\n" ) >= 0 )) { + QFile f ("/etc/oz_version"); + if ( f.exists() ){ + d->m_vendorstr = "OpenZaurus Team"; + d->m_systemstr = "OpenZaurus"; + d->m_system = System_OpenZaurus; + + if ( f. open ( IO_ReadOnly )) { + QTextStream ts ( &f ); + d->m_sysverstr = ts. readLine();//. mid ( 10 ); + f. close(); + } + + // Openzaurus sometimes uses the embedix kernel! + // => Check whether this is an embedix kernel + FILE *uname = popen("uname -r", "r"); + QString line; + if ( f.open(IO_ReadOnly, uname) ) { + QTextStream ts ( &f ); + line = ts. readLine(); + int loc = line. find ( "embedix" ); + if ( loc != -1 ) + m_embedix = true; + else + m_embedix = false; + f. close(); + } + pclose(uname); + } + else { + d->m_systemstr = "Zaurus"; + d->m_system = System_Zaurus; + } + + f. setName ( "/proc/cpuinfo" ); + if ( f. open ( IO_ReadOnly ) ) { + QTextStream ts ( &f ); + QString line; + while( line = ts. readLine() ) { + if ( line. left ( 8 ) == "Hardware" ) + break; + } + int loc = line. find ( ":" ); + if ( loc != -1 ) + model = line. mid ( loc + 2 ). simplifyWhiteSpace( ); + } + + if ( model == "SHARP Corgi" ) { + d->m_model = Model_Zaurus_SLC7x0; + d->m_modelstr = "Zaurus SL-C700"; + } else if ( model == "SHARP Shepherd" ) { + d->m_model = Model_Zaurus_SLC7x0; + d->m_modelstr = "Zaurus SL-C750"; + } else if ( model == "SHARP Husky" ) { + d->m_model = Model_Zaurus_SLC7x0; + d->m_modelstr = "Zaurus SL-C760"; + } else if ( model == "SHARP Poodle" ) { + d->m_model = Model_Zaurus_SLB600; + d->m_modelstr = "Zaurus SL-B500 or SL-5600"; + } else if ( model == "Sharp-Collie" || model == "Collie" ) { + d->m_model = Model_Zaurus_SL5500; + d->m_modelstr = "Zaurus SL-5500 or SL-5000d"; + } else { + d->m_model = Model_Zaurus_SL5500; + d->m_modelstr = "Zaurus (Model unknown)"; + } + + bool flipstate = false; + switch ( d->m_model ) { + case Model_Zaurus_SLA300: + d->m_rotation = Rot0; + break; + case Model_Zaurus_SLC7x0: + d->m_rotation = rotation(); + d->m_direction = direction(); + break; + case Model_Zaurus_SLB600: + case Model_Zaurus_SL5500: + case Model_Zaurus_SL5000: + default: + d->m_rotation = Rot270; + break; + } + m_leds [0] = Led_Off; +} + +void Zaurus::initButtons() +{ + if ( d->m_buttons ) + return; + + d->m_buttons = new QValueList <ODeviceButton>; + + struct z_button * pz_buttons; + int buttoncount; + switch ( d->m_model ) { + case Model_Zaurus_SLC7x0: + pz_buttons = z_buttons_c700; + buttoncount = ARRAY_SIZE(z_buttons_c700); + break; + default: + pz_buttons = z_buttons; + buttoncount = ARRAY_SIZE(z_buttons); + break; + } + + for ( int i = 0; i < buttoncount; i++ ) { + struct z_button *zb = pz_buttons + i; + ODeviceButton b; + + b. setKeycode ( zb->code ); + b. setUserText ( QObject::tr ( "Button", zb->utext )); + b. setPixmap ( Resource::loadPixmap ( zb->pix )); + b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( zb->fpressedservice ), + zb->fpressedaction )); + b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( zb->fheldservice ), + zb->fheldaction )); + + d->m_buttons->append ( b ); + } + + reloadButtonMapping(); + + QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); + connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), + this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); +} + +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +//#include <asm/sharp_char.h> // including kernel headers is evil ... + +#define SHARP_DEV_IOCTL_COMMAND_START 0x5680 + +#define SHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) +#define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START) + +#define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */ +#define SHARP_BUZ_KEYSOUND 2 /* key sound */ +#define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */ + +/* --- for SHARP_BUZZER device --- */ + +//#define SHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) +//#define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START) + +#define SHARP_BUZZER_SETVOLUME (SHARP_BUZZER_IOCTL_START+1) +#define SHARP_BUZZER_GETVOLUME (SHARP_BUZZER_IOCTL_START+2) +#define SHARP_BUZZER_ISSUPPORTED (SHARP_BUZZER_IOCTL_START+3) +#define SHARP_BUZZER_SETMUTE (SHARP_BUZZER_IOCTL_START+4) +#define SHARP_BUZZER_STOPSOUND (SHARP_BUZZER_IOCTL_START+5) + +//#define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */ +//#define SHARP_BUZ_KEYSOUND 2 /* key sound */ + +//#define SHARP_PDA_ILLCLICKSOUND 3 /* illegal click */ +//#define SHARP_PDA_WARNSOUND 4 /* warning occurred */ +//#define SHARP_PDA_ERRORSOUND 5 /* error occurred */ +//#define SHARP_PDA_CRITICALSOUND 6 /* critical error occurred */ +//#define SHARP_PDA_SYSSTARTSOUND 7 /* system start */ +//#define SHARP_PDA_SYSTEMENDSOUND 8 /* system shutdown */ +//#define SHARP_PDA_APPSTART 9 /* application start */ +//#define SHARP_PDA_APPQUIT 10 /* application ends */ + +//#define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */ +//#define SHARP_BUZ_DAILY_ALARM 12 /* daily alarm */ +//#define SHARP_BUZ_GOT_PHONE_CALL 13 /* phone call sound */ +//#define SHARP_BUZ_GOT_MAIL 14 /* mail sound */ +// + +#define SHARP_LED_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) +#define SHARP_LED_SETSTATUS (SHARP_LED_IOCTL_START+1) + +#define SHARP_IOCTL_GET_ROTATION 0x413c + +typedef struct sharp_led_status { +int which; /* select which LED status is wanted. */ +int status; /* set new led status if you call SHARP_LED_SETSTATUS */ +} sharp_led_status; + +#define SHARP_LED_MAIL_EXISTS 9 /* mail status (exists or not) */ + +#define LED_MAIL_NO_UNREAD_MAIL 0 /* for SHARP_LED_MAIL_EXISTS */ +#define LED_MAIL_NEWMAIL_EXISTS 1 /* for SHARP_LED_MAIL_EXISTS */ +#define LED_MAIL_UNREAD_MAIL_EX 2 /* for SHARP_LED_MAIL_EXISTS */ + +// #include <asm/sharp_apm.h> // including kernel headers is evil ... + +#define APM_IOCGEVTSRC OD_IOR( 'A', 203, int ) +#define APM_IOCSEVTSRC OD_IORW( 'A', 204, int ) +#define APM_EVT_POWER_BUTTON (1 << 0) + +#define FL_IOCTL_STEP_CONTRAST 100 + + +void Zaurus::buzzer ( int sound ) +{ +#ifndef QT_NO_SOUND + QString soundname; + + // Not all devices have real sound + if ( d->m_model == Model_Zaurus_SLC7x0 + || d->m_model == Model_Zaurus_SLB600 ){ + + switch ( sound ){ + case SHARP_BUZ_SCHEDULE_ALARM: + soundname = "alarm"; + break; + case SHARP_BUZ_TOUCHSOUND: + soundname = "touchsound"; + break; + case SHARP_BUZ_KEYSOUND: + soundname = "keysound"; + break; + default: + soundname = "alarm"; + + } + } + + // If a soundname is defined, we expect that this device has + // sound capabilities.. Otherwise we expect to have the buzzer + // device.. + if ( !soundname.isEmpty() ){ + int fd; + int vol; + bool vol_reset = false; + + Sound snd ( soundname ); + + if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { + if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { + Config cfg ( "qpe" ); + cfg. setGroup ( "Volume" ); + + int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); + if ( volalarm < 0 ) + volalarm = 0; + else if ( volalarm > 100 ) + volalarm = 100; + volalarm |= ( volalarm << 8 ); + + if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) + vol_reset = true; + } + } + + snd. play(); + while ( !snd. isFinished()) + qApp->processEvents(); + + if ( fd >= 0 ) { + if ( vol_reset ) + ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); + ::close ( fd ); + } + } else { + int fd = ::open ( "/dev/sharp_buz", O_WRONLY|O_NONBLOCK ); + + if ( fd >= 0 ) { + ::ioctl ( fd, SHARP_BUZZER_MAKESOUND, sound ); + ::close ( fd ); + } + + } +#endif +} + + +void Zaurus::alarmSound() +{ + buzzer ( SHARP_BUZ_SCHEDULE_ALARM ); +} + +void Zaurus::touchSound() +{ + buzzer ( SHARP_BUZ_TOUCHSOUND ); +} + +void Zaurus::keySound() +{ + buzzer ( SHARP_BUZ_KEYSOUND ); +} + + +QValueList <OLed> Zaurus::ledList() const +{ + QValueList <OLed> vl; + vl << Led_Mail; + return vl; +} + +QValueList <OLedState> Zaurus::ledStateList ( OLed l ) const +{ + QValueList <OLedState> vl; + + if ( l == Led_Mail ) + vl << Led_Off << Led_On << Led_BlinkSlow; + return vl; +} + +OLedState Zaurus::ledState ( OLed which ) const +{ + if ( which == Led_Mail ) + return m_leds [0]; + else + return Led_Off; +} + +bool Zaurus::setLedState ( OLed which, OLedState st ) +{ + if (!m_embedix) // Currently not supported on non_embedix kernels + return false; + + static int fd = ::open ( "/dev/sharp_led", O_RDWR|O_NONBLOCK ); + + if ( which == Led_Mail ) { + if ( fd >= 0 ) { + struct sharp_led_status leds; + ::memset ( &leds, 0, sizeof( leds )); + leds. which = SHARP_LED_MAIL_EXISTS; + bool ok = true; + + switch ( st ) { + case Led_Off : leds. status = LED_MAIL_NO_UNREAD_MAIL; break; + case Led_On : leds. status = LED_MAIL_NEWMAIL_EXISTS; break; + case Led_BlinkSlow: leds. status = LED_MAIL_UNREAD_MAIL_EX; break; + default : ok = false; + } + + if ( ok && ( ::ioctl ( fd, SHARP_LED_SETSTATUS, &leds ) >= 0 )) { + m_leds [0] = st; + return true; + } + } + } + return false; +} + +bool Zaurus::setSoftSuspend ( bool soft ) +{ + if (!m_embedix) { + /* non-Embedix kernels dont have kernel autosuspend */ + return ODevice::setSoftSuspend( soft ); + } + + bool res = false; + int fd; + + if ((( fd = ::open ( "/dev/apm_bios", O_RDWR )) >= 0 ) || + (( fd = ::open ( "/dev/misc/apm_bios",O_RDWR )) >= 0 )) { + + int sources = ::ioctl ( fd, APM_IOCGEVTSRC, 0 ); // get current event sources + + if ( sources >= 0 ) { + if ( soft ) + sources &= ~APM_EVT_POWER_BUTTON; + else + sources |= APM_EVT_POWER_BUTTON; + + if ( ::ioctl ( fd, APM_IOCSEVTSRC, sources ) >= 0 ) // set new event sources + res = true; + else + perror ( "APM_IOCGEVTSRC" ); + } + else + perror ( "APM_IOCGEVTSRC" ); + + ::close ( fd ); + } + else + perror ( "/dev/apm_bios or /dev/misc/apm_bios" ); + + return res; +} + + +bool Zaurus::setDisplayBrightness ( int bright ) +{ + //qDebug( "Zaurus::setDisplayBrightness( %d )", bright ); + bool res = false; + int fd; + + if ( bright > 255 ) bright = 255; + if ( bright < 0 ) bright = 0; + + if ( m_embedix ) + { + if ( d->m_model == Model_Zaurus_SLC7x0 ) + { + //qDebug( "using special treatment for devices with the corgi backlight interface" ); + // special treatment for devices with the corgi backlight interface + if (( fd = ::open ( "/proc/driver/fl/corgi-bl", O_WRONLY )) >= 0 ) + { + int value = ( bright == 1 ) ? 1 : bright * ( 17.0 / 255.0 ); + char writeCommand[100]; + const int count = sprintf( writeCommand, "0x%x\n", value ); + res = ( ::write ( fd, writeCommand, count ) != -1 ); + ::close ( fd ); + } + return res; + } + else + { + // standard treatment for devices with the dumb embedix frontlight interface + if (( fd = ::open ( "/dev/fl", O_WRONLY )) >= 0 ) { + int bl = ( bright * 4 + 127 ) / 255; // only 4 steps on zaurus + if ( bright && !bl ) + bl = 1; + res = ( ::ioctl ( fd, FL_IOCTL_STEP_CONTRAST, bl ) == 0 ); + ::close ( fd ); + } + } + } + else + { + // special treatment for the OpenZaurus unified interface + #define FB_BACKLIGHT_SET_BRIGHTNESS _IOW('F', 1, u_int) /* set brightness */ + if (( fd = ::open ( "/dev/fb0", O_WRONLY )) >= 0 ) { + res = ( ::ioctl ( fd , FB_BACKLIGHT_SET_BRIGHTNESS, bright ) == 0 ); + ::close ( fd ); + } + } + return res; +} + +bool Zaurus::suspend() +{ + qDebug("ODevice::suspend"); + if ( !isQWS( ) ) // only qwsserver is allowed to suspend + return false; + + if ( d->m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices + return false; + + bool res = false; + + struct timeval tvs, tvn; + ::gettimeofday ( &tvs, 0 ); + + ::sync(); // flush fs caches + res = ( ::system ( "apm --suspend" ) == 0 ); + + // This is needed because the iPAQ apm implementation is asynchronous and we + // can not be sure when exactly the device is really suspended + // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists. + + if ( res ) { + do { // Yes, wait 15 seconds. This APM bug sucks big time. + ::usleep ( 200 * 1000 ); + ::gettimeofday ( &tvn, 0 ); + } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 15000 ); + } + + QCopEnvelope ( "QPE/Rotation", "rotateDefault()" ); + return res; +} + + +Transformation Zaurus::rotation() const +{ + Transformation rot; + int handle = 0; + int retval = 0; + + switch ( d->m_model ) { + case Model_Zaurus_SLC7x0: + handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); + if (handle == -1) { + return Rot270; + } else { + retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); + ::close (handle); + + if (retval == 2 ) + rot = Rot0; + else + rot = Rot270; + } + break; + case Model_Zaurus_SLA300: + case Model_Zaurus_SLB600: + case Model_Zaurus_SL5500: + case Model_Zaurus_SL5000: + default: + rot = d->m_rotation; + break; + } + + return rot; +} +ODirection Zaurus::direction() const +{ + ODirection dir; + int handle = 0; + int retval = 0; + switch ( d->m_model ) { + case Model_Zaurus_SLC7x0: + handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); + if (handle == -1) { + dir = CW; + } else { + retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); + ::close (handle); + if (retval == 2 ) + dir = CCW; + else + dir = CW; + } + break; + case Model_Zaurus_SLA300: + case Model_Zaurus_SLB600: + case Model_Zaurus_SL5500: + case Model_Zaurus_SL5000: + default: + dir = d->m_direction; + break; + } + return dir; + +} + +int Zaurus::displayBrightnessResolution() const +{ + if (m_embedix) + return d->m_model == Model_Zaurus_SLC7x0 ? 18 : 5; + else + return 256; +} + +bool Zaurus::hasHingeSensor() const +{ + return d->m_model == Model_Zaurus_SLC7x0; +} + +OHingeStatus Zaurus::readHingeSensor() +{ + int handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); + if (handle == -1) + { + qWarning("Zaurus::readHingeSensor() - failed (%s)", "unknown reason" ); //FIXME: use strerror + return CASE_UNKNOWN; + } + else + { + int retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); + ::close (handle); + if ( retval == CASE_CLOSED || retval == CASE_PORTRAIT || retval == CASE_LANDSCAPE ) + { + qDebug( "Zaurus::readHingeSensor() - result = %d", retval ); + return static_cast<OHingeStatus>( retval ); + } + else + { + qWarning("Zaurus::readHingeSensor() - couldn't compute hinge status!" ); + return CASE_UNKNOWN; + } + } +} diff --git a/libopie2/opiecore/device/odevicebutton.cpp b/libopie2/opiecore/device/odevicebutton.cpp new file mode 100644 index 0000000..0b593d5 --- a/dev/null +++ b/libopie2/opiecore/device/odevicebutton.cpp @@ -0,0 +1,246 @@ +/* + This file is part of the Opie Project + Copyright (C) The Opie Team <opie-devel@handhelds.org> + =. + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. 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 +..}^=.= = ; 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <qpixmap.h> +#include <qstring.h> + +#include <qpe/qcopenvelope_qws.h> +#include <opie2/odevicebutton.h> + +using namespace Opie; + +class OQCopMessageData +{ + public: + QCString m_channel; + QCString m_message; + QByteArray m_data; +}; + + +OQCopMessage::OQCopMessage() + : d ( 0 ) +{ + init ( QCString(), QCString(), QByteArray()); +} + +OQCopMessage::OQCopMessage ( const OQCopMessage © ) + : d ( 0 ) +{ + init ( copy. channel(), copy. message(), copy. data()); +} + +OQCopMessage &OQCopMessage::operator = ( const OQCopMessage &assign ) +{ + init ( assign. channel(), assign. message(), assign. data()); + return *this; +} + +OQCopMessage::OQCopMessage ( const QCString &ch, const QCString &m, const QByteArray &arg ) + : d ( 0 ) +{ + init ( ch, m, arg ); +} + +void OQCopMessage::init ( const QCString &ch, const QCString &m, const QByteArray &arg ) +{ + if ( !d ) + d = new OQCopMessageData(); + d->m_channel = ch; + d->m_message = m; + d->m_data = arg; +} + +bool OQCopMessage::send() +{ + if ( d->m_channel. isEmpty() || d->m_message. isEmpty() ) + return false; + + QCopEnvelope e ( d->m_channel, d->m_message ); + + if ( d->m_data. size()) + e. writeRawBytes ( d->m_data. data(), d->m_data. size()); + + return true; +} + +QCString OQCopMessage::channel() const +{ + return d->m_channel; +} + +QCString OQCopMessage::message() const +{ + return d->m_message; +} + +QByteArray OQCopMessage::data() const +{ + return d->m_data; +} + +bool OQCopMessage::isNull() const +{ + return d->m_message.isNull() || d->m_channel.isNull(); +} +void OQCopMessage::setChannel ( const QCString &ch ) +{ + d->m_channel = ch; +} + +void OQCopMessage::setMessage ( const QCString &m ) +{ + d->m_message = m; +} + +void OQCopMessage::setData ( const QByteArray &data ) +{ + d->m_data = data; +} + +/*! \class Opie::ODeviceButton + \brief The Opie::ODeviceButton class represents a physical user mappable button on a Qtopia device. + + This class represents a physical button on a Qtopia device. A + device may have "user programmable" buttons. + The location and number of buttons will vary from device to + device. userText() and pixmap() may be used to describe this button + to the user in help documentation. + + \ingroup qtopiaemb + \internal +*/ + +ODeviceButton::ODeviceButton() +{} + +ODeviceButton::~ODeviceButton() +{} + +/*! +Returns the button's keycode. +*/ +ushort ODeviceButton::keycode() const +{ + return m_Keycode; +} + + +/*! +This function returns a human readable, translated description of the button. +*/ +QString ODeviceButton::userText() const +{ + return m_UserText; +} + +/*! +This function returns the pixmap for this button. If there isn't one +it will return an empty (null) pixmap. +*/ +QPixmap ODeviceButton::pixmap() const +{ + return m_Pixmap; +} + +/*! +This function returns the factory preset (default) action for when this button +is pressed. The return value is a legal QCop message. +*/ +OQCopMessage ODeviceButton::factoryPresetPressedAction() const +{ + return m_FactoryPresetPressedAction; +} + +/*! +This function returns the user assigned action for when this button is pressed. +If no action is assigned, factoryPresetAction() is returned. +*/ +OQCopMessage ODeviceButton::pressedAction() const +{ + if (m_PressedAction.channel().isEmpty()) + return factoryPresetPressedAction(); + return m_PressedAction; +} + +/*! +This function returns the factory preset (default) action for when this button +is pressed and held. The return value is a legal QCop message. +*/ +OQCopMessage ODeviceButton::factoryPresetHeldAction() const +{ + return m_FactoryPresetHeldAction; +} + +/*! +This function returns the user assigned action for when this button is pressed +and held. If no action is assigned, factoryPresetAction() is returned. +*/ +OQCopMessage ODeviceButton::heldAction() const +{ + if (m_HeldAction.channel().isEmpty()) + return factoryPresetHeldAction(); + return m_HeldAction; +} + +void ODeviceButton::setKeycode(ushort keycode) +{ + m_Keycode = keycode; +} + +void ODeviceButton::setUserText(const QString& text) +{ + m_UserText = text; +} + +void ODeviceButton::setPixmap(const QPixmap& picture) +{ + m_Pixmap = picture; +} + +void ODeviceButton::setFactoryPresetPressedAction(const OQCopMessage& action) +{ + m_FactoryPresetPressedAction = action; +} + + +void ODeviceButton::setPressedAction(const OQCopMessage& action) +{ + m_PressedAction = action; +} + +void ODeviceButton::setFactoryPresetHeldAction(const OQCopMessage& action) +{ + m_FactoryPresetHeldAction = action; +} + +void ODeviceButton::setHeldAction(const OQCopMessage& action) +{ + m_HeldAction = action; +} diff --git a/libopie2/opiecore/device/odevicebutton.h b/libopie2/opiecore/device/odevicebutton.h new file mode 100644 index 0000000..a66b88f --- a/dev/null +++ b/libopie2/opiecore/device/odevicebutton.h @@ -0,0 +1,108 @@ +/********************************************************************** +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. +** +** This file is part of the Qtopia Environment. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef DEVICE_BUTTON_H +#define DEVICE_BUTTON_H + +#include <qpixmap.h> +#include <qstring.h> + +class OQCopMessageData; + +namespace Opie +{ + +class OQCopMessage +{ +public: + OQCopMessage ( ); + OQCopMessage ( const OQCopMessage © ); + OQCopMessage ( const QCString &m_channel, const QCString &message, const QByteArray &args = QByteArray ( )); + + OQCopMessage &operator = ( const OQCopMessage &assign ); + + void setChannel ( const QCString &channel ); + void setMessage ( const QCString &message ); + void setData ( const QByteArray &ba ); + + QCString channel ( ) const; + QCString message ( ) const; + QByteArray data ( ) const; + + bool isNull()const; + + bool send ( ); + +private: + void init ( const QCString &m_channel, const QCString &message, const QByteArray &args ); + + OQCopMessageData *d; + class Private; + Private* m_data; +}; + + +/** + * This class represents a physical button on a Qtopia device. A device may + * have n "user programmable" buttons, which are number 1..n. The location + * and number of buttons will vary from device to device. userText() and pixmap() + * may be used to describe this button to the user in help documentation. + * + * @version 1.0 + * @author Trolltech + * @short A representation of buttons + */ + +class ODeviceButton +{ + public: + ODeviceButton(); + virtual ~ODeviceButton(); + + ushort keycode ( ) const; + QString userText ( ) const; + QPixmap pixmap ( ) const; + OQCopMessage factoryPresetPressedAction ( ) const; + OQCopMessage pressedAction ( ) const; + OQCopMessage factoryPresetHeldAction ( ) const; + OQCopMessage heldAction ( ) const; + + void setKeycode ( ushort keycode ); + void setUserText ( const QString& text ); + void setPixmap ( const QPixmap& picture ); + void setFactoryPresetPressedAction ( const OQCopMessage& qcopMessage ); + void setPressedAction ( const OQCopMessage& qcopMessage ); + void setFactoryPresetHeldAction ( const OQCopMessage& qcopMessage ); + void setHeldAction ( const OQCopMessage& qcopMessage ); + + private: + ushort m_Keycode; + QString m_UserText; + QPixmap m_Pixmap; + OQCopMessage m_FactoryPresetPressedAction; + OQCopMessage m_PressedAction; + OQCopMessage m_FactoryPresetHeldAction; + OQCopMessage m_HeldAction; + class Private; + Private *d; +}; + +} + +#endif diff --git a/libopie2/opiecore/libopiecore2.control b/libopie2/opiecore/libopiecore2.control index 956d24f..f0a3afc 100644 --- a/libopie2/opiecore/libopiecore2.control +++ b/libopie2/opiecore/libopiecore2.control @@ -4,7 +4,7 @@ Priority: optional Section: opie/system Maintainer: Opie Team <opie@handhelds.org> Architecture: arm -Version: 1.8.2-$SUB_VERSION.2 +Version: 1.8.3-$SUB_VERSION.2 Depends: libqpe1 Provides: libopiecore2 Description: Opie library 2.0 CORE diff --git a/libopie2/opiecore/opiecore.pro b/libopie2/opiecore/opiecore.pro index 237a5ed..97e8146 100644 --- a/libopie2/opiecore/opiecore.pro +++ b/libopie2/opiecore/opiecore.pro @@ -4,20 +4,34 @@ DESTDIR = $(OPIEDIR)/lib HEADERS = oapplication.h \ oconfig.h \ odebug.h \ + odevice.h \ + odevicebutton.h \ oglobal.h \ oglobalsettings.h \ + oprocess.h \ + oprocctrl.h \ ostorageinfo.h SOURCES = oapplication.cpp \ oconfig.cpp \ odebug.cpp \ + odevice.cpp \ + odevicebutton.cpp \ + odevice_ipaq.cpp \ + odevice_jornada.cpp \ + odevice_ramses.cpp \ + odevice_simpad.cpp \ + odevice_zaurus.cpp \ + odevice_yopy.cpp \ oglobal.cpp \ oglobalsettings.cpp \ + oprocess.cpp \ + oprocctrl.cpp \ ostorageinfo.cpp INTERFACES = TARGET = opiecore2 -VERSION = 1.8.2 +VERSION = 1.8.3 INCLUDEPATH += $(OPIEDIR)/include DEPENDPATH += $(OPIEDIR)/include MOC_DIR = moc diff --git a/libopie2/opiecore/oprocctrl.cpp b/libopie2/opiecore/oprocctrl.cpp new file mode 100644 index 0000000..b3d57c8 --- a/dev/null +++ b/libopie2/opiecore/oprocctrl.cpp @@ -0,0 +1,284 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// +// KPROCESSCONTROLLER -- A helper class for KProcess +// +// version 0.3.1, Jan, 8th 1997 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// Ported by Holger Freyther +// + +//#include <config.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> + +#include <qsocketnotifier.h> +#include "oprocess.h" +#include "oprocctrl.h" + +OProcessController *OProcessController::theOProcessController = 0; + +struct sigaction OProcessController::oldChildHandlerData; +bool OProcessController::handlerSet = false; + +OProcessController::OProcessController() +{ + assert( theOProcessController == 0 ); + + if (0 > pipe(fd)) + printf(strerror(errno)); + + notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read); + notifier->setEnabled(true); + QObject::connect(notifier, SIGNAL(activated(int)), + this, SLOT(slotDoHousekeeping(int))); + connect( &delayedChildrenCleanupTimer, SIGNAL( timeout()), + SLOT( delayedChildrenCleanup())); + + theOProcessController = this; + + setupHandlers(); +} + + +void OProcessController::setupHandlers() +{ + if( handlerSet ) + return; + struct sigaction act; + act.sa_handler=theSigCHLDHandler; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGCHLD); + // Make sure we don't block this signal. gdb tends to do that :-( + sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0); + + act.sa_flags = SA_NOCLDSTOP; + + // CC: take care of SunOS which automatically restarts interrupted system + // calls (and thus does not have SA_RESTART) + +#ifdef SA_RESTART + act.sa_flags |= SA_RESTART; +#endif + + sigaction( SIGCHLD, &act, &oldChildHandlerData ); + + act.sa_handler=SIG_IGN; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGPIPE); + act.sa_flags = 0; + sigaction( SIGPIPE, &act, 0L); + handlerSet = true; +} + +void OProcessController::resetHandlers() +{ + if( !handlerSet ) + return; + sigaction( SIGCHLD, &oldChildHandlerData, 0 ); + // there should be no problem with SIGPIPE staying SIG_IGN + handlerSet = false; +} + +// block SIGCHLD handler, because it accesses processList +void OProcessController::addOProcess( OProcess* p ) +{ + sigset_t newset, oldset; + sigemptyset( &newset ); + sigaddset( &newset, SIGCHLD ); + sigprocmask( SIG_BLOCK, &newset, &oldset ); + processList.append( p ); + sigprocmask( SIG_SETMASK, &oldset, 0 ); +} + +void OProcessController::removeOProcess( OProcess* p ) +{ + sigset_t newset, oldset; + sigemptyset( &newset ); + sigaddset( &newset, SIGCHLD ); + sigprocmask( SIG_BLOCK, &newset, &oldset ); + processList.remove( p ); + sigprocmask( SIG_SETMASK, &oldset, 0 ); +} + +//using a struct which contains both the pid and the status makes it easier to write +//and read the data into the pipe +//especially this solves a problem which appeared on my box where slotDoHouseKeeping() received +//only 4 bytes (with some debug output around the write()'s it received all 8 bytes) +//don't know why this happened, but when writing all 8 bytes at once it works here, aleXXX +struct waitdata +{ + pid_t pid; + int status; +}; + +void OProcessController::theSigCHLDHandler(int arg) +{ + struct waitdata wd; + // int status; + // pid_t this_pid; + int saved_errno; + + saved_errno = errno; + // since waitpid and write change errno, we have to save it and restore it + // (Richard Stevens, Advanced programming in the Unix Environment) + + bool found = false; + if( theOProcessController != 0 ) + { + // iterating the list doesn't perform any system call + for( QValueList<OProcess*>::ConstIterator it = theOProcessController->processList.begin(); + it != theOProcessController->processList.end(); + ++it ) + { + if( !(*it)->isRunning()) + continue; + wd.pid = waitpid( (*it)->pid(), &wd.status, WNOHANG ); + if ( wd.pid > 0 ) + { + ::write(theOProcessController->fd[1], &wd, sizeof(wd)); + found = true; + } + } + } + if( !found && oldChildHandlerData.sa_handler != SIG_IGN + && oldChildHandlerData.sa_handler != SIG_DFL ) + oldChildHandlerData.sa_handler( arg ); // call the old handler + // handle the rest + if( theOProcessController != 0 ) + { + static const struct waitdata dwd = { 0, 0 } + ; // delayed waitpid() + ::write(theOProcessController->fd[1], &dwd, sizeof(dwd)); + } + else + { + int dummy; + while( waitpid( -1, &dummy, WNOHANG ) > 0 ) + ; + } + + errno = saved_errno; +} + + + +void OProcessController::slotDoHousekeeping(int ) +{ + unsigned int bytes_read = 0; + unsigned int errcnt=0; + // read pid and status from the pipe. + struct waitdata wd; + while ((bytes_read < sizeof(wd)) && (errcnt < 50)) + { + int r = ::read(fd[0], ((char *)&wd) + bytes_read, sizeof(wd) - bytes_read); + if (r > 0) bytes_read += r; + else if (r < 0) errcnt++; + } + if (errcnt >= 50) + { + fprintf(stderr, + "Error: Max. error count for pipe read " + "exceeded in OProcessController::slotDoHousekeeping\n"); + return; // it makes no sense to continue here! + } + if (bytes_read != sizeof(wd)) + { + fprintf(stderr, + "Error: Could not read info from signal handler %d <> %d!\n", + bytes_read, sizeof(wd)); + return; // it makes no sense to continue here! + } + if (wd.pid==0) + { // special case, see delayedChildrenCleanup() + delayedChildrenCleanupTimer.start( 1000, true ); + return; + } + + for( QValueList<OProcess*>::ConstIterator it = processList.begin(); + it != processList.end(); + ++it ) + { + OProcess* proc = *it; + if (proc->pid() == wd.pid) + { + // process has exited, so do emit the respective events + if (proc->run_mode == OProcess::Block) + { + // If the reads are done blocking then set the status in proc + // but do nothing else because OProcess will perform the other + // actions of processHasExited. + proc->status = wd.status; + proc->runs = false; + } + else + { + proc->processHasExited(wd.status); + } + return; + } + } +} + +// this is needed e.g. for popen(), which calls waitpid() checking +// for its forked child, if we did waitpid() directly in the SIGCHLD +// handler, popen()'s waitpid() call would fail +void OProcessController::delayedChildrenCleanup() +{ + struct waitdata wd; + while(( wd.pid = waitpid( -1, &wd.status, WNOHANG ) ) > 0 ) + { + for( QValueList<OProcess*>::ConstIterator it = processList.begin(); + it != processList.end(); + ++it ) + { + if( !(*it)->isRunning() || (*it)->pid() != wd.pid ) + continue; + // it's OProcess, handle it + ::write(fd[1], &wd, sizeof(wd)); + break; + } + } +} + +OProcessController::~OProcessController() +{ + assert( theOProcessController == this ); + resetHandlers(); + + notifier->setEnabled(false); + + close(fd[0]); + close(fd[1]); + + delete notifier; + theOProcessController = 0; +} + +//#include "kprocctrl.moc" diff --git a/libopie2/opiecore/oprocctrl.h b/libopie2/opiecore/oprocctrl.h new file mode 100644 index 0000000..44b8a48 --- a/dev/null +++ b/libopie2/opiecore/oprocctrl.h @@ -0,0 +1,121 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// +// KPROCESSCONTROLLER -- A helper class for KProcess +// +// version 0.3.1, Jan 8th 1997 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// Ported by Holger Freyther +// + +#ifndef __KPROCCTRL_H__ +#define __KPROCCTRL_H__ + +#include <qvaluelist.h> +#include <qtimer.h> + +#include "oprocess.h" + +class OProcessControllerPrivate; +class QSocketNotifier; + +/** + * @short Used internally by @ref OProcess + * @internal + * @author Christian Czezakte <e9025461@student.tuwien.ac.at> + * + * A class for internal use by OProcess only. -- Exactly one instance + * of this class is generated by the first instance of OProcess that is + * created (a pointer to it gets stored in @ref theOProcessController ). + * + * This class takes care of the actual (UN*X) signal handling. +*/ +class OProcessController : public QObject +{ + Q_OBJECT + +public: + OProcessController(); + ~OProcessController(); + //CC: WARNING! Destructor Not virtual (but you don't derive classes from this anyhow...) + +public: + + /** + * Only a single instance of this class is allowed at a time, + * and this static variable is used to track the one instance. + */ + static OProcessController *theOProcessController; + + /** + * Automatically called upon SIGCHLD. + * + * Normally you do not need to do anything with this function but + * if your application needs to disable SIGCHLD for some time for + * reasons beyond your control, you should call this function afterwards + * to make sure that no SIGCHLDs where missed. + */ + static void theSigCHLDHandler(int signal); + // handler for sigchld + + /** + * @internal + */ + static void setupHandlers(); + /** + * @internal + */ + static void resetHandlers(); + /** + * @internal + */ + void addOProcess( OProcess* ); + /** + * @internal + */ + void removeOProcess( OProcess* ); +public slots: + /** + * @internal + */ + void slotDoHousekeeping(int socket); + +private slots: + void delayedChildrenCleanup(); +private: + int fd[2]; + QSocketNotifier *notifier; + static struct sigaction oldChildHandlerData; + static bool handlerSet; + QValueList<OProcess*> processList; + QTimer delayedChildrenCleanupTimer; + + // Disallow assignment and copy-construction + OProcessController( const OProcessController& ); + OProcessController& operator= ( const OProcessController& ); + + OProcessControllerPrivate *d; +}; + + + +#endif + diff --git a/libopie2/opiecore/oprocess.cpp b/libopie2/opiecore/oprocess.cpp new file mode 100644 index 0000000..fb51bf9 --- a/dev/null +++ b/libopie2/opiecore/oprocess.cpp @@ -0,0 +1,970 @@ +/* + + $Id$ + + This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + + +// +// KPROCESS -- A class for handling child processes in KDE without +// having to take care of Un*x specific implementation details +// +// version 0.3.1, Jan 8th 1998 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// +// Changes: +// +// March 2nd, 1998: Changed parameter list for KShellProcess: +// Arguments are now placed in a single string so that +// <shell> -c <commandstring> is passed to the shell +// to make the use of "operator<<" consistent with KProcess +// +// +// Ported by Holger Freyther +// <zekce> Harlekin: oprocess and say it was ported to Qt by the Opie developers an Qt 2 + + + +#include "oprocess.h" +#define _MAY_INCLUDE_KPROCESSCONTROLLER_ +#include "oprocctrl.h" + +//#include <config.h> + +#include <qfile.h> +#include <qsocketnotifier.h> +#include <qregexp.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#ifdef HAVE_INITGROUPS +#include <grp.h> +#endif +#include <pwd.h> + +#include <qapplication.h> +#include <qmap.h> +//#include <kdebug.h> + +///////////////////////////// +// public member functions // +///////////////////////////// + +class OProcessPrivate +{ +public: + OProcessPrivate() : useShell(false) { } + + bool useShell; + QMap<QString,QString> env; + QString wd; + QCString shell; +}; + + +OProcess::OProcess(QObject *parent, const char *name) + : QObject(parent, name) +{ + init ( ); +} + +OProcess::OProcess(const QString &arg0, QObject *parent, const char *name) + : QObject(parent, name) +{ + init ( ); + *this << arg0; +} + +OProcess::OProcess(const QStringList &args, QObject *parent, const char *name) + : QObject(parent, name) +{ + init ( ); + *this << args; +} + +void OProcess::init ( ) +{ + run_mode = NotifyOnExit; + runs = false; + pid_ = 0; + status = 0; + keepPrivs = false; + innot = 0; + outnot = 0; + errnot = 0; + communication = NoCommunication; + input_data = 0; + input_sent = 0; + input_total = 0; + d = 0; + + if (0 == OProcessController::theOProcessController) + { + (void) new OProcessController(); + CHECK_PTR(OProcessController::theOProcessController); + } + + OProcessController::theOProcessController->addOProcess(this); + out[0] = out[1] = -1; + in[0] = in[1] = -1; + err[0] = err[1] = -1; +} + +void +OProcess::setEnvironment(const QString &name, const QString &value) +{ + if (!d) + d = new OProcessPrivate; + d->env.insert(name, value); +} + +void +OProcess::setWorkingDirectory(const QString &dir) +{ + if (!d) + d = new OProcessPrivate; + d->wd = dir; +} + +void +OProcess::setupEnvironment() +{ + if (d) + { + QMap<QString,QString>::Iterator it; + for(it = d->env.begin(); it != d->env.end(); ++it) + setenv(QFile::encodeName(it.key()).data(), + QFile::encodeName(it.data()).data(), 1); + if (!d->wd.isEmpty()) + chdir(QFile::encodeName(d->wd).data()); + } +} + +void +OProcess::setRunPrivileged(bool keepPrivileges) +{ + keepPrivs = keepPrivileges; +} + +bool +OProcess::runPrivileged() const +{ + return keepPrivs; +} + + +OProcess::~OProcess() +{ + // destroying the OProcess instance sends a SIGKILL to the + // child process (if it is running) after removing it from the + // list of valid processes (if the process is not started as + // "DontCare") + + OProcessController::theOProcessController->removeOProcess(this); + // this must happen before we kill the child + // TODO: block the signal while removing the current process from the process list + + if (runs && (run_mode != DontCare)) + kill(SIGKILL); + + // Clean up open fd's and socket notifiers. + closeStdin(); + closeStdout(); + closeStderr(); + + // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess + delete d; +} + +void OProcess::detach() +{ + OProcessController::theOProcessController->removeOProcess(this); + + runs = false; + pid_ = 0; + + // Clean up open fd's and socket notifiers. + closeStdin(); + closeStdout(); + closeStderr(); +} + +bool OProcess::setExecutable(const QString& proc) +{ + if (runs) return false; + + if (proc.isEmpty()) return false; + + if (!arguments.isEmpty()) + arguments.remove(arguments.begin()); + arguments.prepend(QFile::encodeName(proc)); + + return true; +} + +OProcess &OProcess::operator<<(const QStringList& args) +{ + QStringList::ConstIterator it = args.begin(); + for ( ; it != args.end() ; ++it ) + arguments.append(QFile::encodeName(*it)); + return *this; +} + +OProcess &OProcess::operator<<(const QCString& arg) +{ + return operator<< (arg.data()); +} + +OProcess &OProcess::operator<<(const char* arg) +{ + arguments.append(arg); + return *this; +} + +OProcess &OProcess::operator<<(const QString& arg) +{ + arguments.append(QFile::encodeName(arg)); + return *this; +} + +void OProcess::clearArguments() +{ + arguments.clear(); +} + +bool OProcess::start(RunMode runmode, Communication comm) +{ + uint i; + uint n = arguments.count(); + char **arglist; + + if (runs || (0 == n)) + { + return false; // cannot start a process that is already running + // or if no executable has been assigned + } + run_mode = runmode; + status = 0; + + QCString shellCmd; + if (d && d->useShell) + { + if (d->shell.isEmpty()) + { + qWarning( "Could not find a valid shell" ); + return false; + } + + arglist = static_cast<char **>(malloc( (4)*sizeof(char *))); + for (i=0; i < n; i++) + { + shellCmd += arguments[i]; + shellCmd += " "; // CC: to separate the arguments + } + + arglist[0] = d->shell.data(); + arglist[1] = (char *) "-c"; + arglist[2] = shellCmd.data(); + arglist[3] = 0; + } + else + { + arglist = static_cast<char **>(malloc( (n+1)*sizeof(char *))); + for (i=0; i < n; i++) + arglist[i] = arguments[i].data(); + arglist[n]= 0; + } + + if (!setupCommunication(comm)) + qWarning( "Could not setup Communication!"); + + // We do this in the parent because if we do it in the child process + // gdb gets confused when the application runs from gdb. + uid_t uid = getuid(); + gid_t gid = getgid(); +#ifdef HAVE_INITGROUPS + struct passwd *pw = getpwuid(uid); +#endif + + int fd[2]; + if (0 > pipe(fd)) + { + fd[0] = fd[1] = 0; // Pipe failed.. continue + } + + runs = true; + + QApplication::flushX(); + + // WABA: Note that we use fork() and not vfork() because + // vfork() has unclear semantics and is not standardized. + pid_ = fork(); + + if (0 == pid_) + { + if (fd[0]) + close(fd[0]); + if (!runPrivileged()) + { + setgid(gid); +#if defined( HAVE_INITGROUPS) + if(pw) + initgroups(pw->pw_name, pw->pw_gid); +#endif + setuid(uid); + } + // The child process + if(!commSetupDoneC()) + qWarning( "Could not finish comm setup in child!" ); + + setupEnvironment(); + + // Matthias + if (run_mode == DontCare) + setpgid(0,0); + // restore default SIGPIPE handler (Harri) + struct sigaction act; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGPIPE); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigaction(SIGPIPE, &act, 0L); + + // We set the close on exec flag. + // Closing of fd[1] indicates that the execvp succeeded! + if (fd[1]) + fcntl(fd[1], F_SETFD, FD_CLOEXEC); + execvp(arglist[0], arglist); + char resultByte = 1; + if (fd[1]) + write(fd[1], &resultByte, 1); + _exit(-1); + } + else if (-1 == pid_) + { + // forking failed + + runs = false; + free(arglist); + return false; + } + else + { + if (fd[1]) + close(fd[1]); + // the parent continues here + + // Discard any data for stdin that might still be there + input_data = 0; + + // Check whether client could be started. + if (fd[0]) for(;;) + { + char resultByte; + int n = ::read(fd[0], &resultByte, 1); + if (n == 1) + { + // Error + runs = false; + close(fd[0]); + free(arglist); + pid_ = 0; + return false; + } + if (n == -1) + { + if ((errno == ECHILD) || (errno == EINTR)) + continue; // Ignore + } + break; // success + } + if (fd[0]) + close(fd[0]); + + if (!commSetupDoneP()) // finish communication socket setup for the parent + qWarning( "Could not finish comm setup in parent!" ); + + if (run_mode == Block) + { + commClose(); + + // The SIGCHLD handler of the process controller will catch + // the exit and set the status + while(runs) + { + OProcessController::theOProcessController-> + slotDoHousekeeping(0); + } + runs = FALSE; + emit processExited(this); + } + } + free(arglist); + return true; +} + + + +bool OProcess::kill(int signo) +{ + bool rv=false; + + if (0 != pid_) + rv= (-1 != ::kill(pid_, signo)); + // probably store errno somewhere... + return rv; +} + + + +bool OProcess::isRunning() const +{ + return runs; +} + + + +pid_t OProcess::pid() const +{ + return pid_; +} + + + +bool OProcess::normalExit() const +{ + int _status = status; + return (pid_ != 0) && (!runs) && (WIFEXITED((_status))); +} + + + +int OProcess::exitStatus() const +{ + int _status = status; + return WEXITSTATUS((_status)); +} + + + +bool OProcess::writeStdin(const char *buffer, int buflen) +{ + bool rv; + + // if there is still data pending, writing new data + // to stdout is not allowed (since it could also confuse + // kprocess... + if (0 != input_data) + return false; + + if (runs && (communication & Stdin)) + { + input_data = buffer; + input_sent = 0; + input_total = buflen; + slotSendData(0); + innot->setEnabled(true); + rv = true; + } + else + rv = false; + return rv; +} + +void OProcess::flushStdin ( ) +{ + if ( !input_data || ( input_sent == input_total )) + return; + + int d1, d2; + + do + { + d1 = input_total - input_sent; + slotSendData ( 0 ); + d2 = input_total - input_sent; + } + while ( d2 <= d1 ); +} + +void OProcess::suspend() +{ + if ((communication & Stdout) && outnot) + outnot->setEnabled(false); +} + +void OProcess::resume() +{ + if ((communication & Stdout) && outnot) + outnot->setEnabled(true); +} + +bool OProcess::closeStdin() +{ + bool rv; + + if (communication & Stdin) + { + communication = (Communication) (communication & ~Stdin); + delete innot; + innot = 0; + close(in[1]); + rv = true; + } + else + rv = false; + return rv; +} + +bool OProcess::closeStdout() +{ + bool rv; + + if (communication & Stdout) + { + communication = (Communication) (communication & ~Stdout); + delete outnot; + outnot = 0; + close(out[0]); + rv = true; + } + else + rv = false; + return rv; +} + +bool OProcess::closeStderr() +{ + bool rv; + + if (communication & Stderr) + { + communication = static_cast<Communication>(communication & ~Stderr); + delete errnot; + errnot = 0; + close(err[0]); + rv = true; + } + else + rv = false; + return rv; +} + + +///////////////////////////// +// protected slots // +///////////////////////////// + + + +void OProcess::slotChildOutput(int fdno) +{ + if (!childOutput(fdno)) + closeStdout(); +} + + +void OProcess::slotChildError(int fdno) +{ + if (!childError(fdno)) + closeStderr(); +} + + +void OProcess::slotSendData(int) +{ + if (input_sent == input_total) + { + innot->setEnabled(false); + input_data = 0; + emit wroteStdin(this); + } + else + input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent); +} + + + +////////////////////////////// +// private member functions // +////////////////////////////// + + + +void OProcess::processHasExited(int state) +{ + if (runs) + { + runs = false; + status = state; + + commClose(); // cleanup communication sockets + + // also emit a signal if the process was run Blocking + if (DontCare != run_mode) + { + emit processExited(this); + } + } +} + + + +int OProcess::childOutput(int fdno) +{ + if (communication & NoRead) + { + int len = -1; + emit receivedStdout(fdno, len); + errno = 0; // Make sure errno doesn't read "EAGAIN" + return len; + } + else + { + char buffer[1024]; + int len; + + len = ::read(fdno, buffer, 1024); + + if ( 0 < len) + { + emit receivedStdout(this, buffer, len); + } + return len; + } +} + + + +int OProcess::childError(int fdno) +{ + char buffer[1024]; + int len; + + len = ::read(fdno, buffer, 1024); + + if ( 0 < len) + emit receivedStderr(this, buffer, len); + return len; +} + + + +int OProcess::setupCommunication(Communication comm) +{ + int ok; + + communication = comm; + + ok = 1; + if (comm & Stdin) + ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, in) >= 0; + + if (comm & Stdout) + ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, out) >= 0; + + if (comm & Stderr) + ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, err) >= 0; + + return ok; +} + + + +int OProcess::commSetupDoneP() +{ + int ok = 1; + + if (communication != NoCommunication) + { + if (communication & Stdin) + close(in[0]); + if (communication & Stdout) + close(out[1]); + if (communication & Stderr) + close(err[1]); + + // Don't create socket notifiers and set the sockets non-blocking if + // blocking is requested. + if (run_mode == Block) return ok; + + if (communication & Stdin) + { + // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK)); + innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this); + CHECK_PTR(innot); + innot->setEnabled(false); // will be enabled when data has to be sent + QObject::connect(innot, SIGNAL(activated(int)), + this, SLOT(slotSendData(int))); + } + + if (communication & Stdout) + { + // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK)); + outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this); + CHECK_PTR(outnot); + QObject::connect(outnot, SIGNAL(activated(int)), + this, SLOT(slotChildOutput(int))); + if (communication & NoRead) + suspend(); + } + + if (communication & Stderr) + { + // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK)); + errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this ); + CHECK_PTR(errnot); + QObject::connect(errnot, SIGNAL(activated(int)), + this, SLOT(slotChildError(int))); + } + } + return ok; +} + + + +int OProcess::commSetupDoneC() +{ + int ok = 1; + struct linger so; + memset(&so, 0, sizeof(so)); + + if (communication & Stdin) + close(in[1]); + if (communication & Stdout) + close(out[0]); + if (communication & Stderr) + close(err[0]); + + if (communication & Stdin) + ok &= dup2(in[0], STDIN_FILENO) != -1; + else + { + int null_fd = open( "/dev/null", O_RDONLY ); + ok &= dup2( null_fd, STDIN_FILENO ) != -1; + close( null_fd ); + } + if (communication & Stdout) + { + ok &= dup2(out[1], STDOUT_FILENO) != -1; + ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so)); + } + else + { + int null_fd = open( "/dev/null", O_WRONLY ); + ok &= dup2( null_fd, STDOUT_FILENO ) != -1; + close( null_fd ); + } + if (communication & Stderr) + { + ok &= dup2(err[1], STDERR_FILENO) != -1; + ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&so), sizeof(so)); + } + else + { + int null_fd = open( "/dev/null", O_WRONLY ); + ok &= dup2( null_fd, STDERR_FILENO ) != -1; + close( null_fd ); + } + return ok; +} + + + +void OProcess::commClose() +{ + if (NoCommunication != communication) + { + bool b_in = (communication & Stdin); + bool b_out = (communication & Stdout); + bool b_err = (communication & Stderr); + if (b_in) + delete innot; + + if (b_out || b_err) + { + // If both channels are being read we need to make sure that one socket buffer + // doesn't fill up whilst we are waiting for data on the other (causing a deadlock). + // Hence we need to use select. + + // Once one or other of the channels has reached EOF (or given an error) go back + // to the usual mechanism. + + int fds_ready = 1; + fd_set rfds; + + int max_fd = 0; + if (b_out) + { + fcntl(out[0], F_SETFL, O_NONBLOCK); + if (out[0] > max_fd) + max_fd = out[0]; + delete outnot; + outnot = 0; + } + if (b_err) + { + fcntl(err[0], F_SETFL, O_NONBLOCK); + if (err[0] > max_fd) + max_fd = err[0]; + delete errnot; + errnot = 0; + } + + + while (b_out || b_err) + { + // * If the process is still running we block until we + // receive data. (p_timeout = 0, no timeout) + // * If the process has already exited, we only check + // the available data, we don't wait for more. + // (p_timeout = &timeout, timeout immediately) + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + struct timeval *p_timeout = runs ? 0 : &timeout; + + FD_ZERO(&rfds); + if (b_out) + FD_SET(out[0], &rfds); + + if (b_err) + FD_SET(err[0], &rfds); + + fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout); + if (fds_ready <= 0) break; + + if (b_out && FD_ISSET(out[0], &rfds)) + { + int ret = 1; + while (ret > 0) ret = childOutput(out[0]); + if ((ret == -1 && errno != EAGAIN) || ret == 0) + b_out = false; + } + + if (b_err && FD_ISSET(err[0], &rfds)) + { + int ret = 1; + while (ret > 0) ret = childError(err[0]); + if ((ret == -1 && errno != EAGAIN) || ret == 0) + b_err = false; + } + } + } + + if (b_in) + { + communication = (Communication) (communication & ~Stdin); + close(in[1]); + } + if (b_out) + { + communication = (Communication) (communication & ~Stdout); + close(out[0]); + } + if (b_err) + { + communication = (Communication) (communication & ~Stderr); + close(err[0]); + } + } +} + +void OProcess::setUseShell(bool useShell, const char *shell) +{ + if (!d) + d = new OProcessPrivate; + d->useShell = useShell; + d->shell = shell; + if (d->shell.isEmpty()) + d->shell = searchShell(); +} + +QString OProcess::quote(const QString &arg) +{ + QString res = arg; + res.replace(QRegExp(QString::fromLatin1("\'")), + QString::fromLatin1("'\"'\"'")); + res.prepend('\''); + res.append('\''); + return res; +} + +QCString OProcess::searchShell() +{ + QCString tmpShell = QCString(getenv("SHELL")).stripWhiteSpace(); + if (!isExecutable(tmpShell)) + { + tmpShell = "/bin/sh"; + } + + return tmpShell; +} + +bool OProcess::isExecutable(const QCString &filename) +{ + struct stat fileinfo; + + if (filename.isEmpty()) return false; + + // CC: we've got a valid filename, now let's see whether we can execute that file + + if (-1 == stat(filename.data(), &fileinfo)) return false; + // CC: return false if the file does not exist + + // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets + if ( (S_ISDIR(fileinfo.st_mode)) || + (S_ISCHR(fileinfo.st_mode)) || + (S_ISBLK(fileinfo.st_mode)) || +#ifdef S_ISSOCK + // CC: SYSVR4 systems don't have that macro + (S_ISSOCK(fileinfo.st_mode)) || +#endif + (S_ISFIFO(fileinfo.st_mode)) || + (S_ISDIR(fileinfo.st_mode)) ) + { + return false; + } + + // CC: now check for permission to execute the file + if (access(filename.data(), X_OK) != 0) return false; + + // CC: we've passed all the tests... + return true; +} + + + diff --git a/libopie2/opiecore/oprocess.h b/libopie2/opiecore/oprocess.h new file mode 100644 index 0000000..8dd19b5 --- a/dev/null +++ b/libopie2/opiecore/oprocess.h @@ -0,0 +1,747 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) + + 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +// +// KPROCESS -- A class for handling child processes in KDE without +// having to take care of Un*x specific implementation details +// +// version 0.3.1, Jan 8th 1998 +// +// (C) Christian Czezatke +// e9025461@student.tuwien.ac.at +// Ported by Holger Freyther to the Open Palmtop Integrated Environment +// + +#ifndef __kprocess_h__ +#define __kprocess_h__ + +#include <sys/types.h> // for pid_t +#include <sys/wait.h> +#include <signal.h> +#include <unistd.h> +#include <qvaluelist.h> +#include <qcstring.h> +#include <qobject.h> + +class QSocketNotifier; +class OProcessPrivate; + +/** + * Child process invocation, monitoring and control. + * + * @sect General usage and features + * + *This class allows a KDE and OPIE application to start child processes without having + *to worry about UN*X signal handling issues and zombie process reaping. + * + *@see KProcIO + * + *Basically, this class distinguishes three different ways of running + *child processes: + * + *@li OProcess::DontCare -- The child process is invoked and both the child + *process and the parent process continue concurrently. + * + *Starting a DontCare child process means that the application is + *not interested in any notification to determine whether the + *child process has already exited or not. + * + *@li OProcess::NotifyOnExit -- The child process is invoked and both the + *child and the parent process run concurrently. + * + *When the child process exits, the OProcess instance + *corresponding to it emits the Qt signal @ref processExited(). + * + *Since this signal is @em not emitted from within a UN*X + *signal handler, arbitrary function calls can be made. + * + *Be aware: When the OProcess objects gets destructed, the child + *process will be killed if it is still running! + *This means in particular, that you cannot use a OProcess on the stack + *with OProcess::NotifyOnExit. + * + *@li OProcess::Block -- The child process starts and the parent process + *is suspended until the child process exits. (@em Really not recommended + *for programs with a GUI.) + * + *OProcess also provides several functions for determining the exit status + *and the pid of the child process it represents. + * + *Furthermore it is possible to supply command-line arguments to the process + *in a clean fashion (no null -- terminated stringlists and such...) + * + *A small usage example: + *<pre> + *OProcess *proc = new OProcess; + * + **proc << "my_executable"; + **proc << "These" << "are" << "the" << "command" << "line" << "args"; + *QApplication::connect(proc, SIGNAL(processExited(OProcess *)), + * pointer_to_my_object, SLOT(my_objects_slot(OProcess *))); + *proc->start(); + *</pre> + * + *This will start "my_executable" with the commandline arguments "These"... + * + *When the child process exits, the respective Qt signal will be emitted. + * + *@sect Communication with the child process + * + *OProcess supports communication with the child process through + *stdin/stdout/stderr. + * + *The following functions are provided for getting data from the child + *process or sending data to the child's stdin (For more information, + *have a look at the documentation of each function): + * + *@li bool @ref writeStdin(char *buffer, int buflen); + *@li -- Transmit data to the child process's stdin. + * + *@li bool @ref closeStdin(); + *@li -- Closes the child process's stdin (which causes it to see an feof(stdin)). + *Returns false if you try to close stdin for a process that has been started + *without a communication channel to stdin. + * + *@li bool @ref closeStdout(); + *@li -- Closes the child process's stdout. + *Returns false if you try to close stdout for a process that has been started + *without a communication channel to stdout. + * + *@li bool @ref closeStderr(); + *@li -- Closes the child process's stderr. + *Returns false if you try to close stderr for a process that has been started + *without a communication channel to stderr. + * + * + *@sect QT signals: + * + *@li void @ref receivedStdout(OProcess *proc, char *buffer, int buflen); + *@li void @ref receivedStderr(OProcess *proc, char *buffer, int buflen); + *@li -- Indicates that new data has arrived from either the + *child process's stdout or stderr. + * + *@li void @ref wroteStdin(OProcess *proc); + *@li -- Indicates that all data that has been sent to the child process + *by a prior call to @ref writeStdin() has actually been transmitted to the + *client . + * + *@author Christian Czezakte e9025461@student.tuwien.ac.at + * + * + **/ +class OProcess : public QObject +{ + Q_OBJECT + +public: + + /** + * Modes in which the communication channel can be opened. + * + * If communication for more than one channel is required, + * the values have to be or'ed together, for example to get + * communication with stdout as well as with stdin, you would + * specify @p Stdin @p | @p Stdout + * + * If @p NoRead is specified in conjunction with @p Stdout, + * no data is actually read from @p Stdout but only + * the signal @ref childOutput(int fd) is emitted. + */ + enum Communication { NoCommunication = 0, Stdin = 1, Stdout = 2, Stderr = 4, + AllOutput = 6, All = 7, + NoRead }; + + /** + * Run-modes for a child process. + */ + enum RunMode { + /** + * The application does not receive notifications from the subprocess when + * it is finished or aborted. + */ + DontCare, + /** + * The application is notified when the subprocess dies. + */ + NotifyOnExit, + /** + * The application is suspended until the started process is finished. + */ + Block }; + + /** + * Constructor + */ + OProcess(QObject *parent = 0, const char *name = 0); + /** + * Constructor + */ + OProcess(const QString &arg0, QObject *parent = 0, const char *name = 0); + /** + * Constructor + */ + OProcess(const QStringList &args, QObject *parent = 0, const char *name = 0); + + /** + *Destructor: + * + * If the process is running when the destructor for this class + * is called, the child process is killed with a SIGKILL, but + * only if the run mode is not of type @p DontCare. + * Processes started as @p DontCare keep running anyway. + */ + virtual ~OProcess(); + + /** + @deprecated + + The use of this function is now deprecated. -- Please use the + "operator<<" instead of "setExecutable". + + Sets the executable to be started with this OProcess object. + Returns false if the process is currently running (in that + case the executable remains unchanged.) + + @see operator<< + + */ + bool setExecutable(const QString& proc); + + + /** + * Sets the executable and the command line argument list for this process. + * + * For example, doing an "ls -l /usr/local/bin" can be achieved by: + * <pre> + * OProcess p; + * ... + * p << "ls" << "-l" << "/usr/local/bin" + * </pre> + * + **/ + OProcess &operator<<(const QString& arg); + /** + * Similar to previous method, takes a char *, supposed to be in locale 8 bit already. + */ + OProcess &operator<<(const char * arg); + /** + * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already. + */ + OProcess &operator<<(const QCString & arg); + + /** + * Sets the executable and the command line argument list for this process, + * in a single method call, or add a list of arguments. + **/ + OProcess &operator<<(const QStringList& args); + + /** + * Clear a command line argument list that has been set by using + * the "operator<<". + */ + void clearArguments(); + + /** + * Starts the process. + * For a detailed description of the + * various run modes and communication semantics, have a look at the + * general description of the OProcess class. + * + * The following problems could cause this function to + * return false: + * + * @li The process is already running. + * @li The command line argument list is empty. + * @li The starting of the process failed (could not fork). + * @li The executable was not found. + * + * @param comm Specifies which communication links should be + * established to the child process (stdin/stdout/stderr). By default, + * no communication takes place and the respective communication + * signals will never get emitted. + * + * @return true on success, false on error + * (see above for error conditions) + **/ + virtual bool start(RunMode runmode = NotifyOnExit, + Communication comm = NoCommunication); + + /** + * Stop the process (by sending it a signal). + * + * @param signo The signal to send. The default is SIGTERM. + * @return @p true if the signal was delivered successfully. + */ + virtual bool kill(int signo = SIGTERM); + + /** + @return @p true if the process is (still) considered to be running + */ + bool isRunning() const; + + /** Returns the process id of the process. + * + * If it is called after + * the process has exited, it returns the process id of the last + * child process that was created by this instance of OProcess. + * + * Calling it before any child process has been started by this + * OProcess instance causes pid() to return 0. + **/ + pid_t pid() const; + + /** + * Suspend processing of data from stdout of the child process. + */ + void suspend(); + + /** + * Resume processing of data from stdout of the child process. + */ + void resume(); + + /** + * @return @p true if the process has already finished and has exited + * "voluntarily", ie: it has not been killed by a signal. + * + * Note that you should check @ref OProcess::exitStatus() to determine + * whether the process completed its task successful or not. + */ + bool normalExit() const; + + /** + * Returns the exit status of the process. + * + * Please use + * @ref OProcess::normalExit() to check whether the process has exited + * cleanly (i.e., @ref OProcess::normalExit() returns @p true) before calling + * this function because if the process did not exit normally, + * it does not have a valid exit status. + */ + int exitStatus() const; + + + /** + * Transmit data to the child process's stdin. + * + * OProcess::writeStdin may return false in the following cases: + * + * @li The process is not currently running. + * + * @li Communication to stdin has not been requested in the @ref start() call. + * + * @li Transmission of data to the child process by a previous call to + * @ref writeStdin() is still in progress. + * + * Please note that the data is sent to the client asynchronously, + * so when this function returns, the data might not have been + * processed by the child process. + * + * If all the data has been sent to the client, the signal + * @ref wroteStdin() will be emitted. + * + * Please note that you must not free "buffer" or call @ref writeStdin() + * again until either a @ref wroteStdin() signal indicates that the + * data has been sent or a @ref processHasExited() signal shows that + * the child process is no longer alive... + **/ + bool writeStdin(const char *buffer, int buflen); + + void flushStdin(); + + /** + * This causes the stdin file descriptor of the child process to be + * closed indicating an "EOF" to the child. + * + * @return @p false if no communication to the process's stdin + * had been specified in the call to @ref start(). + */ + bool closeStdin(); + + /** + * This causes the stdout file descriptor of the child process to be + * closed. + * + * @return @p false if no communication to the process's stdout + * had been specified in the call to @ref start(). + */ + bool closeStdout(); + + /** + * This causes the stderr file descriptor of the child process to be + * closed. + * + * @return @p false if no communication to the process's stderr + * had been specified in the call to @ref start(). + */ + bool closeStderr(); + + /** + * Lets you see what your arguments are for debugging. + */ + + const QValueList<QCString> &args() { return arguments; } + + /** + * Controls whether the started process should drop any + * setuid/segid privileges or whether it should keep them + * + * The default is @p false : drop privileges + */ + void setRunPrivileged(bool keepPrivileges); + + /** + * Returns whether the started process will drop any + * setuid/segid privileges or whether it will keep them + */ + bool runPrivileged() const; + + /** + * Modifies the environment of the process to be started. + * This function must be called before starting the process. + */ + void setEnvironment(const QString &name, const QString &value); + + /** + * Changes the current working directory (CWD) of the process + * to be started. + * This function must be called before starting the process. + */ + void setWorkingDirectory(const QString &dir); + + /** + * Specify whether to start the command via a shell or directly. + * The default is to start the command directly. + * If @p useShell is true @p shell will be used as shell, or + * if shell is empty, the standard shell is used. + * @p quote A flag indicating whether to quote the arguments. + * + * When using a shell, the caller should make sure that all filenames etc. + * are properly quoted when passed as argument. + * @see quote() + */ + void setUseShell(bool useShell, const char *shell = 0); + + /** + * This function can be used to quote an argument string such that + * the shell processes it properly. This is e. g. necessary for + * user-provided file names which may contain spaces or quotes. + * It also prevents expansion of wild cards and environment variables. + */ + static QString quote(const QString &arg); + + /** + * Detaches OProcess from child process. All communication is closed. + * No exit notification is emitted any more for the child process. + * Deleting the OProcess will no longer kill the child process. + * Note that the current process remains the parent process of the + * child process. + */ + void detach(); + + + +signals: + + /** + * Emitted after the process has terminated when + * the process was run in the @p NotifyOnExit (==default option to + * @ref start()) or the @ref Block mode. + **/ + void processExited(OProcess *proc); + + + /** + * Emitted, when output from the child process has + * been received on stdout. + * + * To actually get + * these signals, the respective communication link (stdout/stderr) + * has to be turned on in @ref start(). + * + * @param buffer The data received. + * @param buflen The number of bytes that are available. + * + * You should copy the information contained in @p buffer to your private + * data structures before returning from this slot. + **/ + void receivedStdout(OProcess *proc, char *buffer, int buflen); + + /** + * Emitted when output from the child process has + * been received on stdout. + * + * To actually get these signals, the respective communications link + * (stdout/stderr) has to be turned on in @ref start() and the + * @p NoRead flag should have been passed. + * + * You will need to explicitly call resume() after your call to start() + * to begin processing data from the child process's stdout. This is + * to ensure that this signal is not emitted when no one is connected + * to it, otherwise this signal will not be emitted. + * + * The data still has to be read from file descriptor @p fd. + **/ + void receivedStdout(int fd, int &len); + + + /** + * Emitted, when output from the child process has + * been received on stderr. + * To actually get + * these signals, the respective communication link (stdout/stderr) + * has to be turned on in @ref start(). + * + * @param buffer The data received. + * @param buflen The number of bytes that are available. + * + * You should copy the information contained in @p buffer to your private + * data structures before returning from this slot. + */ + void receivedStderr(OProcess *proc, char *buffer, int buflen); + + /** + * Emitted after all the data that has been + * specified by a prior call to @ref writeStdin() has actually been + * written to the child process. + **/ + void wroteStdin(OProcess *proc); + + +protected slots: + + /** + * This slot gets activated when data from the child's stdout arrives. + * It usually calls "childOutput" + */ + void slotChildOutput(int fdno); + + /** + * This slot gets activated when data from the child's stderr arrives. + * It usually calls "childError" + */ + void slotChildError(int fdno); + /* + Slot functions for capturing stdout and stderr of the child + */ + + /** + * Called when another bulk of data can be sent to the child's + * stdin. If there is no more data to be sent to stdin currently + * available, this function must disable the QSocketNotifier "innot". + */ + void slotSendData(int dummy); + +protected: + + /** + * Sets up the environment according to the data passed via + * setEnvironment(...) + */ + void setupEnvironment(); + + /** + * The list of the process' command line arguments. The first entry + * in this list is the executable itself. + */ + QValueList<QCString> arguments; + /** + * How to run the process (Block, NotifyOnExit, DontCare). You should + * not modify this data member directly from derived classes. + */ + RunMode run_mode; + /** + * true if the process is currently running. You should not + * modify this data member directly from derived classes. For + * reading the value of this data member, please use "isRunning()" + * since "runs" will probably be made private in later versions + * of OProcess. + */ + bool runs; + + /** + * The PID of the currently running process (see "getPid()"). + * You should not modify this data member in derived classes. + * Please use "getPid()" instead of directly accessing this + * member function since it will probably be made private in + * later versions of OProcess. + */ + pid_t pid_; + + /** + * The process' exit status as returned by "waitpid". You should not + * modify the value of this data member from derived classes. You should + * rather use @ref exitStatus than accessing this data member directly + * since it will probably be made private in further versions of + * OProcess. + */ + int status; + + + /** + * See setRunPrivileged() + */ + bool keepPrivs; + + /* + Functions for setting up the sockets for communication. + setupCommunication + -- is called from "start" before "fork"ing. + commSetupDoneP + -- completes communication socket setup in the parent + commSetupDoneC + -- completes communication setup in the child process + commClose + -- frees all allocated communication resources in the parent + after the process has exited + */ + + /** + * This function is called from "OProcess::start" right before a "fork" takes + * place. According to + * the "comm" parameter this function has to initialize the "in", "out" and + * "err" data member of OProcess. + * + * This function should return 0 if setting the needed communication channels + * was successful. + * + * The default implementation is to create UNIX STREAM sockets for the communication, + * but you could overload this function and establish a TCP/IP communication for + * network communication, for example. + */ + virtual int setupCommunication(Communication comm); + + /** + * Called right after a (successful) fork on the parent side. This function + * will usually do some communications cleanup, like closing the reading end + * of the "stdin" communication channel. + * + * Furthermore, it must also create the QSocketNotifiers "innot", "outnot" and + * "errnot" and connect their Qt slots to the respective OProcess member functions. + * + * For a more detailed explanation, it is best to have a look at the default + * implementation of "setupCommunication" in kprocess.cpp. + */ + virtual int commSetupDoneP(); + + /** + * Called right after a (successful) fork, but before an "exec" on the child + * process' side. It usually just closes the unused communication ends of + * "in", "out" and "err" (like the writing end of the "in" communication + * channel. + */ + virtual int commSetupDoneC(); + + + /** + * Immediately called after a process has exited. This function normally + * calls commClose to close all open communication channels to this + * process and emits the "processExited" signal (if the process was + * not running in the "DontCare" mode). + */ + virtual void processHasExited(int state); + + /** + * Should clean up the communication links to the child after it has + * exited. Should be called from "processHasExited". + */ + virtual void commClose(); + + + /** + * the socket descriptors for stdin/stdout/stderr. + */ + int out[2]; + int in[2]; + int err[2]; + + /** + * The socket notifiers for the above socket descriptors. + */ + QSocketNotifier *innot; + QSocketNotifier *outnot; + QSocketNotifier *errnot; + + /** + * Lists the communication links that are activated for the child + * process. Should not be modified from derived classes. + */ + Communication communication; + + /** + * Called by "slotChildOutput" this function copies data arriving from the + * child process's stdout to the respective buffer and emits the signal + * "@ref receivedStderr". + */ + int childOutput(int fdno); + + /** + * Called by "slotChildOutput" this function copies data arriving from the + * child process's stdout to the respective buffer and emits the signal + * "@ref receivedStderr" + */ + int childError(int fdno); + + // information about the data that has to be sent to the child: + + const char *input_data; // the buffer holding the data + int input_sent; // # of bytes already transmitted + int input_total; // total length of input_data + + /** + * @ref OProcessController is a friend of OProcess because it has to have + * access to various data members. + */ + friend class OProcessController; + + +private: + /** + * Searches for a valid shell. + * Here is the algorithm used for finding an executable shell: + * + * @li Try the executable pointed to by the "SHELL" environment + * variable with white spaces stripped off + * + * @li If your process runs with uid != euid or gid != egid, a shell + * not listed in /etc/shells will not used. + * + * @li If no valid shell could be found, "/bin/sh" is used as a last resort. + */ + QCString searchShell(); + + /** + * Used by @ref searchShell in order to find out whether the shell found + * is actually executable at all. + */ + bool isExecutable(const QCString &filename); + + // Disallow assignment and copy-construction + OProcess( const OProcess& ); + OProcess& operator= ( const OProcess& ); + +private: + void init ( ); + + OProcessPrivate *d; +}; + + + +#endif + diff --git a/libopie2/opienet/libopienet2.control b/libopie2/opienet/libopienet2.control index 8eb0704..a45eb2d 100644 --- a/libopie2/opienet/libopienet2.control +++ b/libopie2/opienet/libopienet2.control @@ -4,8 +4,8 @@ Priority: optional Section: opie/system Maintainer: Opie Team <opie@handhelds.org> Architecture: arm -Version: 1.8.2-$SUB_VERSION.2 -Depends: libopiecore2 (1.8.2) +Version: 1.8.3-$SUB_VERSION +Depends: libopiecore2 (1.8.3) Provides: libopienet2 Description: Opie library 2.0 NET |