author | mickeyl <mickeyl> | 2004-01-13 15:21:40 (UTC) |
---|---|---|
committer | mickeyl <mickeyl> | 2004-01-13 15:21:40 (UTC) |
commit | af79bda4c7e51f46abe67124f9c06126eaebb59d (patch) (unidiff) | |
tree | 4e9ad77ec4b2bb3d66ac6553d0a225b0b18f2140 /libopie2/opiecore | |
parent | 24eb97ec5cda3d72c3541fd120568b8d937025f8 (diff) | |
download | opie-af79bda4c7e51f46abe67124f9c06126eaebb59d.zip opie-af79bda4c7e51f46abe67124f9c06126eaebb59d.tar.gz opie-af79bda4c7e51f46abe67124f9c06126eaebb59d.tar.bz2 |
- split odevice into dedicated files and classes, it has getting much too large
- merge odevice into libopie2
- merge oprocctrl and oprocess into libopie2
-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 |
16 files changed, 5944 insertions, 2 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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include "odevice.h" | ||
31 | |||
32 | /* QT */ | ||
33 | #include <qapplication.h> | ||
34 | #include <qfile.h> | ||
35 | #include <qtextstream.h> | ||
36 | #include <qwindowsystem_qws.h> | ||
37 | |||
38 | /* OPIE */ | ||
39 | #include <qpe/config.h> | ||
40 | #include <qpe/resource.h> | ||
41 | #include <qpe/sound.h> | ||
42 | #include <qpe/qcopenvelope_qws.h> | ||
43 | |||
44 | /* STD */ | ||
45 | #include <fcntl.h> | ||
46 | #include <math.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <signal.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/time.h> | ||
51 | #include <unistd.h> | ||
52 | #ifndef QT_NO_SOUND | ||
53 | #include <linux/soundcard.h> | ||
54 | #endif | ||
55 | |||
56 | #ifndef ARRAY_SIZE | ||
57 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
58 | #endif | ||
59 | |||
60 | // _IO and friends are only defined in kernel headers ... | ||
61 | |||
62 | #define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) | ||
63 | |||
64 | #define OD_IO(type,number) OD_IOC(0,type,number,0) | ||
65 | #define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) | ||
66 | #define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) | ||
67 | #define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) | ||
68 | |||
69 | using namespace Opie; | ||
70 | |||
71 | class iPAQ; | ||
72 | class Zaurus; | ||
73 | class SIMpad; | ||
74 | class Ramses; | ||
75 | class Jornada; | ||
76 | |||
77 | ODevice *ODevice::inst() | ||
78 | { | ||
79 | static ODevice *dev = 0; | ||
80 | |||
81 | // rewrite this to only use /proc/devinfo or so | ||
82 | |||
83 | /* | ||
84 | if ( !dev ) { | ||
85 | if ( QFile::exists ( "/proc/hal/model" )) | ||
86 | dev = new iPAQ(); | ||
87 | else if ( Zaurus::isZaurus() ) | ||
88 | dev = new Zaurus(); | ||
89 | else if ( QFile::exists ( "/proc/ucb1x00" ) && QFile::exists ( "/proc/cs3" )) | ||
90 | dev = new SIMpad(); | ||
91 | else if ( QFile::exists ( "/proc/sys/board/name" )) | ||
92 | dev = new Ramses(); | ||
93 | else if ( Yopy::isYopy() ) | ||
94 | dev = new Yopy(); | ||
95 | else if ( Jornada::isJornada() ) | ||
96 | dev = new Jornada(); | ||
97 | else | ||
98 | dev = new ODevice(); | ||
99 | dev->init(); | ||
100 | } | ||
101 | */ | ||
102 | return dev; | ||
103 | } | ||
104 | |||
105 | ODevice::ODevice() | ||
106 | { | ||
107 | d = new ODeviceData; | ||
108 | |||
109 | d->m_modelstr = "Unknown"; | ||
110 | d->m_model = Model_Unknown; | ||
111 | d->m_vendorstr = "Unknown"; | ||
112 | d->m_vendor = Vendor_Unknown; | ||
113 | d->m_systemstr = "Unknown"; | ||
114 | d->m_system = System_Unknown; | ||
115 | d->m_sysverstr = "0.0"; | ||
116 | d->m_rotation = Rot0; | ||
117 | d->m_direction = CW; | ||
118 | |||
119 | d->m_holdtime = 1000; // 1000ms | ||
120 | d->m_buttons = 0; | ||
121 | d->m_cpu_frequencies = new QStrList; | ||
122 | } | ||
123 | |||
124 | void ODevice::systemMessage ( const QCString &msg, const QByteArray & ) | ||
125 | { | ||
126 | if ( msg == "deviceButtonMappingChanged()" ) { | ||
127 | reloadButtonMapping(); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | void ODevice::init() | ||
132 | { | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * This method initialises the button mapping | ||
137 | */ | ||
138 | void ODevice::initButtons() | ||
139 | { | ||
140 | if ( d->m_buttons ) | ||
141 | return; | ||
142 | |||
143 | qDebug ( "init Buttons" ); | ||
144 | d->m_buttons = new QValueList <ODeviceButton>; | ||
145 | |||
146 | reloadButtonMapping(); | ||
147 | |||
148 | QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); | ||
149 | connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); | ||
150 | } | ||
151 | |||
152 | ODevice::~ODevice() | ||
153 | { | ||
154 | // we leak m_devicebuttons and m_cpu_frequency | ||
155 | // but it's a singleton and it is not so importantant | ||
156 | // -zecke | ||
157 | delete d; | ||
158 | } | ||
159 | |||
160 | bool ODevice::setSoftSuspend ( bool /*soft*/ ) | ||
161 | { | ||
162 | return false; | ||
163 | } | ||
164 | |||
165 | //#include <linux/apm_bios.h> | ||
166 | |||
167 | #define APM_IOC_SUSPEND OD_IO( 'A', 2 ) | ||
168 | |||
169 | /** | ||
170 | * This method will try to suspend the device | ||
171 | * It only works if the user is the QWS Server and the apm application | ||
172 | * is installed. | ||
173 | * It tries to suspend and then waits some time cause some distributions | ||
174 | * do have asynchronus apm implementations. | ||
175 | * This method will either fail and return false or it'll suspend the | ||
176 | * device and return once the device got woken up | ||
177 | * | ||
178 | * @return if the device got suspended | ||
179 | */ | ||
180 | bool ODevice::suspend() | ||
181 | { | ||
182 | qDebug("ODevice::suspend"); | ||
183 | if ( !isQWS( ) ) // only qwsserver is allowed to suspend | ||
184 | return false; | ||
185 | |||
186 | if ( d->m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices | ||
187 | return false; | ||
188 | |||
189 | bool res = false; | ||
190 | |||
191 | struct timeval tvs, tvn; | ||
192 | ::gettimeofday ( &tvs, 0 ); | ||
193 | |||
194 | ::sync(); // flush fs caches | ||
195 | res = ( ::system ( "apm --suspend" ) == 0 ); | ||
196 | |||
197 | // This is needed because the iPAQ apm implementation is asynchronous and we | ||
198 | // can not be sure when exactly the device is really suspended | ||
199 | // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists. | ||
200 | |||
201 | if ( res ) { | ||
202 | do { // wait at most 1.5 sec: either suspend didn't work or the device resumed | ||
203 | ::usleep ( 200 * 1000 ); | ||
204 | ::gettimeofday ( &tvn, 0 ); | ||
205 | } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 1500 ); | ||
206 | } | ||
207 | |||
208 | return res; | ||
209 | } | ||
210 | |||
211 | //#include <linux/fb.h> better not rely on kernel headers in userspace ... | ||
212 | |||
213 | #define FBIOBLANK OD_IO( 'F', 0x11 ) // 0x4611 | ||
214 | |||
215 | /* VESA Blanking Levels */ | ||
216 | #define VESA_NO_BLANKING 0 | ||
217 | #define VESA_VSYNC_SUSPEND 1 | ||
218 | #define VESA_HSYNC_SUSPEND 2 | ||
219 | #define VESA_POWERDOWN 3 | ||
220 | |||
221 | /** | ||
222 | * This sets the display on or off | ||
223 | */ | ||
224 | bool ODevice::setDisplayStatus ( bool on ) | ||
225 | { | ||
226 | qDebug("ODevice::setDisplayStatus(%d)", on); | ||
227 | |||
228 | if ( d->m_model == Model_Unknown ) | ||
229 | return false; | ||
230 | |||
231 | bool res = false; | ||
232 | int fd; | ||
233 | |||
234 | if (( fd = ::open ( "/dev/fb0", O_RDWR )) >= 0 ) { | ||
235 | res = ( ::ioctl ( fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN ) == 0 ); | ||
236 | ::close ( fd ); | ||
237 | } | ||
238 | return res; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * This sets the display brightness | ||
243 | * | ||
244 | * @param p The brightness to be set on a scale from 0 to 255 | ||
245 | * @return success or failure | ||
246 | */ | ||
247 | bool ODevice::setDisplayBrightness ( int p) | ||
248 | { | ||
249 | Q_UNUSED( p ) | ||
250 | return false; | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * @return returns the number of steppings on the brightness slider | ||
255 | * in the Light-'n-Power settings. | ||
256 | */ | ||
257 | int ODevice::displayBrightnessResolution() const | ||
258 | { | ||
259 | return 16; | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * This sets the display contrast | ||
264 | * @param p The contrast to be set on a scale from 0 to 255 | ||
265 | * @return success or failure | ||
266 | */ | ||
267 | bool ODevice::setDisplayContrast ( int p) | ||
268 | { | ||
269 | Q_UNUSED( p ) | ||
270 | return false; | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * @return return the max value for the brightness settings slider | ||
275 | * or 0 if the device doesn't support setting of a contrast | ||
276 | */ | ||
277 | int ODevice::displayContrastResolution() const | ||
278 | { | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * This returns the vendor as string | ||
284 | * @return Vendor as QString | ||
285 | */ | ||
286 | QString ODevice::vendorString() const | ||
287 | { | ||
288 | return d->m_vendorstr; | ||
289 | } | ||
290 | |||
291 | /** | ||
292 | * This returns the vendor as one of the values of OVendor | ||
293 | * @return OVendor | ||
294 | */ | ||
295 | OVendor ODevice::vendor() const | ||
296 | { | ||
297 | return d->m_vendor; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * This returns the model as a string | ||
302 | * @return A string representing the model | ||
303 | */ | ||
304 | QString ODevice::modelString() const | ||
305 | { | ||
306 | return d->m_modelstr; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * This does return the OModel used | ||
311 | */ | ||
312 | OModel ODevice::model() const | ||
313 | { | ||
314 | return d->m_model; | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * This does return the systen name | ||
319 | */ | ||
320 | QString ODevice::systemString() const | ||
321 | { | ||
322 | return d->m_systemstr; | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * Return System as OSystem value | ||
327 | */ | ||
328 | OSystem ODevice::system() const | ||
329 | { | ||
330 | return d->m_system; | ||
331 | } | ||
332 | |||
333 | /** | ||
334 | * @return the version string of the base system | ||
335 | */ | ||
336 | QString ODevice::systemVersionString() const | ||
337 | { | ||
338 | return d->m_sysverstr; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * @return the current Transformation | ||
343 | */ | ||
344 | Transformation ODevice::rotation() const | ||
345 | { | ||
346 | return d->m_rotation; | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * @return the current rotation direction | ||
351 | */ | ||
352 | ODirection ODevice::direction() const | ||
353 | { | ||
354 | return d->m_direction; | ||
355 | } | ||
356 | |||
357 | /** | ||
358 | * This plays an alarmSound | ||
359 | */ | ||
360 | void ODevice::alarmSound() | ||
361 | { | ||
362 | #ifndef QT_NO_SOUND | ||
363 | static Sound snd ( "alarm" ); | ||
364 | |||
365 | if ( snd. isFinished()) | ||
366 | snd. play(); | ||
367 | #endif | ||
368 | } | ||
369 | |||
370 | /** | ||
371 | * This plays a key sound | ||
372 | */ | ||
373 | void ODevice::keySound() | ||
374 | { | ||
375 | #ifndef QT_NO_SOUND | ||
376 | static Sound snd ( "keysound" ); | ||
377 | |||
378 | if ( snd. isFinished()) | ||
379 | snd. play(); | ||
380 | #endif | ||
381 | } | ||
382 | |||
383 | /** | ||
384 | * This plays a touch sound | ||
385 | */ | ||
386 | void ODevice::touchSound() | ||
387 | { | ||
388 | #ifndef QT_NO_SOUND | ||
389 | static Sound snd ( "touchsound" ); | ||
390 | |||
391 | if ( snd. isFinished()) | ||
392 | snd. play(); | ||
393 | #endif | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * This method will return a list of leds | ||
398 | * available on this device | ||
399 | * @return a list of LEDs. | ||
400 | */ | ||
401 | QValueList <OLed> ODevice::ledList() const | ||
402 | { | ||
403 | return QValueList <OLed>(); | ||
404 | } | ||
405 | |||
406 | /** | ||
407 | * This does return the state of the LEDs | ||
408 | */ | ||
409 | QValueList <OLedState> ODevice::ledStateList ( OLed /*which*/ ) const | ||
410 | { | ||
411 | return QValueList <OLedState>(); | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * @return the state for a given OLed | ||
416 | */ | ||
417 | OLedState ODevice::ledState ( OLed /*which*/ ) const | ||
418 | { | ||
419 | return Led_Off; | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * Set the state for a LED | ||
424 | * @param which Which OLed to use | ||
425 | * @param st The state to set | ||
426 | * @return success or failure | ||
427 | */ | ||
428 | bool ODevice::setLedState ( OLed which, OLedState st ) | ||
429 | { | ||
430 | Q_UNUSED( which ) | ||
431 | Q_UNUSED( st ) | ||
432 | return false; | ||
433 | } | ||
434 | |||
435 | /** | ||
436 | * @return if the device has a light sensor | ||
437 | */ | ||
438 | bool ODevice::hasLightSensor() const | ||
439 | { | ||
440 | return false; | ||
441 | } | ||
442 | |||
443 | /** | ||
444 | * @return a value from the light sensor | ||
445 | */ | ||
446 | int ODevice::readLightSensor() | ||
447 | { | ||
448 | return -1; | ||
449 | } | ||
450 | |||
451 | /** | ||
452 | * @return the light sensor resolution | ||
453 | */ | ||
454 | int ODevice::lightSensorResolution() const | ||
455 | { | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /** | ||
460 | * @return if the device has a hinge sensor | ||
461 | */ | ||
462 | bool ODevice::hasHingeSensor() const | ||
463 | { | ||
464 | return false; | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * @return a value from the hinge sensor | ||
469 | */ | ||
470 | OHingeStatus ODevice::readHingeSensor() | ||
471 | { | ||
472 | return CASE_UNKNOWN; | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * @return a list with CPU frequencies supported by the hardware | ||
477 | */ | ||
478 | const QStrList &ODevice::allowedCpuFrequencies() const | ||
479 | { | ||
480 | return *d->m_cpu_frequencies; | ||
481 | } | ||
482 | |||
483 | |||
484 | /** | ||
485 | * Set desired CPU frequency | ||
486 | * | ||
487 | * @param index index into d->m_cpu_frequencies of the frequency to be set | ||
488 | */ | ||
489 | bool ODevice::setCurrentCpuFrequency(uint index) | ||
490 | { | ||
491 | if (index >= d->m_cpu_frequencies->count()) | ||
492 | return false; | ||
493 | |||
494 | char *freq = d->m_cpu_frequencies->at(index); | ||
495 | qWarning("set freq to %s", freq); | ||
496 | |||
497 | int fd; | ||
498 | |||
499 | if ((fd = ::open("/proc/sys/cpu/0/speed", O_WRONLY)) >= 0) { | ||
500 | char writeCommand[50]; | ||
501 | const int count = sprintf(writeCommand, "%s\n", freq); | ||
502 | int res = (::write(fd, writeCommand, count) != -1); | ||
503 | ::close(fd); | ||
504 | return res; | ||
505 | } | ||
506 | |||
507 | return false; | ||
508 | } | ||
509 | |||
510 | |||
511 | /** | ||
512 | * @return a list of hardware buttons | ||
513 | */ | ||
514 | const QValueList <ODeviceButton> &ODevice::buttons() | ||
515 | { | ||
516 | initButtons(); | ||
517 | |||
518 | return *d->m_buttons; | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * @return The amount of time that would count as a hold | ||
523 | */ | ||
524 | uint ODevice::buttonHoldTime() const | ||
525 | { | ||
526 | return d->m_holdtime; | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * This method return a ODeviceButton for a key code | ||
531 | * or 0 if no special hardware button is available for the device | ||
532 | * | ||
533 | * @return The devicebutton or 0l | ||
534 | * @see ODeviceButton | ||
535 | */ | ||
536 | const ODeviceButton *ODevice::buttonForKeycode ( ushort code ) | ||
537 | { | ||
538 | initButtons(); | ||
539 | |||
540 | for ( QValueListConstIterator<ODeviceButton> it = d->m_buttons->begin(); it != d->m_buttons->end(); ++it ) { | ||
541 | if ( (*it). keycode() == code ) | ||
542 | return &(*it); | ||
543 | } | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | void ODevice::reloadButtonMapping() | ||
548 | { | ||
549 | initButtons(); | ||
550 | |||
551 | Config cfg ( "ButtonSettings" ); | ||
552 | |||
553 | for ( uint i = 0; i < d->m_buttons->count(); i++ ) { | ||
554 | ODeviceButton &b = ( *d->m_buttons ) [i]; | ||
555 | QString group = "Button" + QString::number ( i ); | ||
556 | |||
557 | QCString pch, hch; | ||
558 | QCString pm, hm; | ||
559 | QByteArray pdata, hdata; | ||
560 | |||
561 | if ( cfg. hasGroup ( group )) { | ||
562 | cfg. setGroup ( group ); | ||
563 | pch = cfg. readEntry ( "PressedActionChannel" ). latin1(); | ||
564 | pm = cfg. readEntry ( "PressedActionMessage" ). latin1(); | ||
565 | // pdata = decodeBase64 ( buttonFile. readEntry ( "PressedActionArgs" )); | ||
566 | |||
567 | hch = cfg. readEntry ( "HeldActionChannel" ). latin1(); | ||
568 | hm = cfg. readEntry ( "HeldActionMessage" ). latin1(); | ||
569 | // hdata = decodeBase64 ( buttonFile. readEntry ( "HeldActionArgs" )); | ||
570 | } | ||
571 | |||
572 | b. setPressedAction ( OQCopMessage ( pch, pm, pdata )); | ||
573 | |||
574 | b. setHeldAction ( OQCopMessage ( hch, hm, hdata )); | ||
575 | } | ||
576 | } | ||
577 | |||
578 | void ODevice::remapPressedAction ( int button, const OQCopMessage &action ) | ||
579 | { | ||
580 | initButtons(); | ||
581 | |||
582 | QString mb_chan; | ||
583 | |||
584 | if ( button >= (int) d->m_buttons->count()) | ||
585 | return; | ||
586 | |||
587 | ODeviceButton &b = ( *d->m_buttons ) [button]; | ||
588 | b. setPressedAction ( action ); | ||
589 | |||
590 | mb_chan=b. pressedAction(). channel(); | ||
591 | |||
592 | Config buttonFile ( "ButtonSettings" ); | ||
593 | buttonFile. setGroup ( "Button" + QString::number ( button )); | ||
594 | buttonFile. writeEntry ( "PressedActionChannel", (const char*) mb_chan); | ||
595 | buttonFile. writeEntry ( "PressedActionMessage", (const char*) b. pressedAction(). message()); | ||
596 | |||
597 | //buttonFile. writeEntry ( "PressedActionArgs", encodeBase64 ( b. pressedAction(). data())); | ||
598 | |||
599 | QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" ); | ||
600 | } | ||
601 | |||
602 | void ODevice::remapHeldAction ( int button, const OQCopMessage &action ) | ||
603 | { | ||
604 | initButtons(); | ||
605 | |||
606 | if ( button >= (int) d->m_buttons->count()) | ||
607 | return; | ||
608 | |||
609 | ODeviceButton &b = ( *d->m_buttons ) [button]; | ||
610 | b. setHeldAction ( action ); | ||
611 | |||
612 | Config buttonFile ( "ButtonSettings" ); | ||
613 | buttonFile. setGroup ( "Button" + QString::number ( button )); | ||
614 | buttonFile. writeEntry ( "HeldActionChannel", (const char *) b. heldAction(). channel()); | ||
615 | buttonFile. writeEntry ( "HeldActionMessage", (const char *) b. heldAction(). message()); | ||
616 | |||
617 | //buttonFile. writeEntry ( "HeldActionArgs", decodeBase64 ( b. heldAction(). data())); | ||
618 | |||
619 | QCopEnvelope ( "QPE/System", "deviceButtonMappingChanged()" ); | ||
620 | } | ||
621 | void ODevice::virtual_hook(int, void* ){ | ||
622 | |||
623 | } | ||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #ifndef ODEVICE_H_ | ||
31 | #define ODEVICE_H_ | ||
32 | |||
33 | #include <opie2/odevicebutton.h> | ||
34 | |||
35 | /* QT */ | ||
36 | #include <qnamespace.h> | ||
37 | #include <qobject.h> | ||
38 | #include <qstring.h> | ||
39 | #include <qstrlist.h> | ||
40 | |||
41 | #include <qpe/qpeapplication.h> /* for Transformation enum.. */ | ||
42 | |||
43 | namespace Opie | ||
44 | { | ||
45 | class ODeviceData; | ||
46 | /** | ||
47 | * The available devices | ||
48 | */ | ||
49 | enum OModel { | ||
50 | Model_Unknown, // = 0 | ||
51 | |||
52 | Model_Series_Mask = 0xff000000, | ||
53 | |||
54 | Model_iPAQ = ( 1 << 24 ), | ||
55 | |||
56 | Model_iPAQ_All = ( Model_iPAQ | 0xffffff ), | ||
57 | Model_iPAQ_H31xx = ( Model_iPAQ | 0x000001 ), | ||
58 | Model_iPAQ_H36xx = ( Model_iPAQ | 0x000002 ), | ||
59 | Model_iPAQ_H37xx = ( Model_iPAQ | 0x000004 ), | ||
60 | Model_iPAQ_H38xx = ( Model_iPAQ | 0x000008 ), | ||
61 | Model_iPAQ_H39xx = ( Model_iPAQ | 0x000010 ), | ||
62 | Model_iPAQ_H5xxx = ( Model_iPAQ | 0x000011 ), | ||
63 | |||
64 | Model_Jornada = ( 6 << 24 ), | ||
65 | Model_Jornada_56x = ( Model_Jornada | 0x000001 ), | ||
66 | |||
67 | Model_Zaurus = ( 2 << 24 ), | ||
68 | |||
69 | Model_Zaurus_SL5000 = ( Model_Zaurus | 0x000001 ), | ||
70 | Model_Zaurus_SL5500 = ( Model_Zaurus | 0x000002 ), | ||
71 | Model_Zaurus_SLA300 = ( Model_Zaurus | 0x000003 ), | ||
72 | Model_Zaurus_SLB600 = ( Model_Zaurus | 0x000004 ), | ||
73 | Model_Zaurus_SLC7x0 = ( Model_Zaurus | 0x000005 ), | ||
74 | |||
75 | Model_SIMpad = ( 3 << 24 ), | ||
76 | |||
77 | Model_SIMpad_All = ( Model_SIMpad | 0xffffff ), | ||
78 | Model_SIMpad_CL4 = ( Model_SIMpad | 0x000001 ), | ||
79 | Model_SIMpad_SL4 = ( Model_SIMpad | 0x000002 ), | ||
80 | Model_SIMpad_SLC = ( Model_SIMpad | 0x000004 ), | ||
81 | Model_SIMpad_TSinus = ( Model_SIMpad | 0x000008 ), | ||
82 | |||
83 | Model_Ramses = ( 4 << 24 ), | ||
84 | |||
85 | Model_Ramses_All = ( Model_Ramses | 0xffffff ), | ||
86 | Model_Ramses_MNCI = ( Model_Ramses | 0x000001 ), | ||
87 | |||
88 | Model_Yopy = ( 5 << 24 ), | ||
89 | |||
90 | Model_Yopy_All = ( Model_Yopy | 0xffffff ), | ||
91 | Model_Yopy_3000 = ( Model_Yopy | 0x000001 ), | ||
92 | Model_Yopy_3500 = ( Model_Yopy | 0x000002 ), | ||
93 | Model_Yopy_3700 = ( Model_Yopy | 0x000003 ), | ||
94 | |||
95 | }; | ||
96 | |||
97 | /** | ||
98 | * The vendor of the device | ||
99 | */ | ||
100 | enum OVendor { | ||
101 | Vendor_Unknown, | ||
102 | |||
103 | Vendor_HP, | ||
104 | Vendor_Sharp, | ||
105 | Vendor_SIEMENS, | ||
106 | Vendor_MundN, | ||
107 | Vendor_GMate, | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * The System used | ||
112 | */ | ||
113 | enum OSystem { | ||
114 | System_Unknown, | ||
115 | |||
116 | System_Familiar, | ||
117 | System_Zaurus, | ||
118 | System_OpenZaurus, | ||
119 | System_Linupy, | ||
120 | }; | ||
121 | |||
122 | enum OLedState { | ||
123 | Led_Off, | ||
124 | Led_On, | ||
125 | Led_BlinkSlow, | ||
126 | Led_BlinkFast | ||
127 | }; | ||
128 | |||
129 | enum OLed { | ||
130 | Led_Mail, | ||
131 | Led_Power, | ||
132 | Led_BlueTooth | ||
133 | }; | ||
134 | |||
135 | enum OHardKey { | ||
136 | HardKey_Datebook = Qt::Key_F9, | ||
137 | HardKey_Contacts = Qt::Key_F10, | ||
138 | HardKey_Menu = Qt::Key_F11, | ||
139 | HardKey_Home = Qt::Key_F12, | ||
140 | HardKey_Mail = Qt::Key_F13, | ||
141 | HardKey_Record = Qt::Key_F24, | ||
142 | HardKey_Suspend = Qt::Key_F34, | ||
143 | HardKey_Backlight = Qt::Key_F35, | ||
144 | HardKey_Action = Qt::Key_F10, | ||
145 | HardKey_OK = Qt::Key_F11, | ||
146 | HardKey_End = Qt::Key_F12, | ||
147 | }; | ||
148 | |||
149 | enum ODirection { | ||
150 | CW = 0, | ||
151 | CCW = 1, | ||
152 | Flip = 2, | ||
153 | }; | ||
154 | |||
155 | enum OHingeStatus { | ||
156 | CASE_CLOSED = 3, | ||
157 | CASE_PORTRAIT = 2, | ||
158 | CASE_LANDSCAPE = 0, | ||
159 | CASE_UNKNOWN = 1, | ||
160 | }; | ||
161 | |||
162 | /** | ||
163 | * A singleton which gives informations about device specefic option | ||
164 | * like the Hardware used, LEDs, the Base Distribution and | ||
165 | * hardware key mappings. | ||
166 | * | ||
167 | * @short A small class for device specefic options | ||
168 | * @see QObject | ||
169 | * @author Robert Griebl | ||
170 | * @version 1.0 | ||
171 | */ | ||
172 | class ODevice : public QObject | ||
173 | { | ||
174 | Q_OBJECT | ||
175 | |||
176 | private: | ||
177 | /* disable copy */ | ||
178 | ODevice ( const ODevice & ); | ||
179 | |||
180 | protected: | ||
181 | ODevice(); | ||
182 | virtual void init(); | ||
183 | virtual void initButtons(); | ||
184 | |||
185 | ODeviceData *d; | ||
186 | |||
187 | public: | ||
188 | // sandman do we want to allow destructions? -zecke? | ||
189 | virtual ~ODevice(); | ||
190 | |||
191 | static ODevice *inst(); | ||
192 | |||
193 | // information | ||
194 | |||
195 | QString modelString() const; | ||
196 | OModel model() const; | ||
197 | inline OModel series() const { return (OModel) ( model() & Model_Series_Mask ); } | ||
198 | |||
199 | QString vendorString() const; | ||
200 | OVendor vendor() const; | ||
201 | |||
202 | QString systemString() const; | ||
203 | OSystem system() const; | ||
204 | |||
205 | QString systemVersionString() const; | ||
206 | |||
207 | virtual Transformation rotation() const; | ||
208 | virtual ODirection direction() const; | ||
209 | |||
210 | // system | ||
211 | |||
212 | virtual bool setSoftSuspend ( bool on ); | ||
213 | virtual bool suspend(); | ||
214 | |||
215 | virtual bool setDisplayStatus ( bool on ); | ||
216 | virtual bool setDisplayBrightness ( int brightness ); | ||
217 | virtual int displayBrightnessResolution() const; | ||
218 | virtual bool setDisplayContrast ( int contrast ); | ||
219 | virtual int displayContrastResolution() const; | ||
220 | |||
221 | // don't add new virtual methods, use this: | ||
222 | ///*virtual */ void boo(int i ) { return virtual_hook(1,&i); }; | ||
223 | // and in your subclass do do overwrite | ||
224 | //protected virtual int virtual_hook(int, void *) | ||
225 | // which is defined below | ||
226 | |||
227 | // input / output | ||
228 | //FIXME playAlarmSound and al might be better -zecke | ||
229 | virtual void alarmSound(); | ||
230 | virtual void keySound(); | ||
231 | virtual void touchSound(); | ||
232 | |||
233 | virtual QValueList <OLed> ledList() const; | ||
234 | virtual QValueList <OLedState> ledStateList ( OLed led ) const; | ||
235 | virtual OLedState ledState ( OLed led ) const; | ||
236 | virtual bool setLedState ( OLed led, OLedState st ); | ||
237 | |||
238 | virtual bool hasLightSensor() const; | ||
239 | virtual int readLightSensor(); | ||
240 | virtual int lightSensorResolution() const; | ||
241 | |||
242 | virtual bool hasHingeSensor() const; | ||
243 | virtual OHingeStatus readHingeSensor(); | ||
244 | |||
245 | const QStrList &allowedCpuFrequencies() const; | ||
246 | bool setCurrentCpuFrequency(uint index); | ||
247 | |||
248 | /** | ||
249 | * Returns the available buttons on this device. The number and location | ||
250 | * of buttons will vary depending on the device. Button numbers will be assigned | ||
251 | * by the device manufacturer and will be from most preferred button to least preffered | ||
252 | * button. Note that this list only contains "user mappable" buttons. | ||
253 | */ | ||
254 | const QValueList<ODeviceButton> &buttons() /* ### make const */; | ||
255 | |||
256 | /** | ||
257 | * Returns the DeviceButton for the \a keyCode. If \a keyCode is not found, it | ||
258 | * returns 0L | ||
259 | */ | ||
260 | const ODeviceButton *buttonForKeycode ( ushort keyCode ); | ||
261 | |||
262 | /** | ||
263 | * Reassigns the pressed action for \a button. To return to the factory | ||
264 | * default pass an empty string as \a qcopMessage. | ||
265 | */ | ||
266 | void remapPressedAction ( int button, const OQCopMessage &qcopMessage ); | ||
267 | |||
268 | /** | ||
269 | * Reassigns the held action for \a button. To return to the factory | ||
270 | * default pass an empty string as \a qcopMessage. | ||
271 | */ | ||
272 | void remapHeldAction ( int button, const OQCopMessage &qcopMessage ); | ||
273 | |||
274 | /** | ||
275 | * How long (in ms) you have to press a button for a "hold" action | ||
276 | */ | ||
277 | uint buttonHoldTime() const; | ||
278 | |||
279 | signals: | ||
280 | void buttonMappingChanged(); | ||
281 | |||
282 | private slots: | ||
283 | void systemMessage ( const QCString &, const QByteArray & ); | ||
284 | |||
285 | protected: | ||
286 | void reloadButtonMapping(); | ||
287 | /* ugly virtual hook */ | ||
288 | virtual void virtual_hook( int id, void* data ); | ||
289 | }; | ||
290 | |||
291 | class ODeviceData { | ||
292 | |||
293 | public: | ||
294 | QString m_vendorstr; | ||
295 | OVendor m_vendor; | ||
296 | |||
297 | QString m_modelstr; | ||
298 | OModel m_model; | ||
299 | |||
300 | QString m_systemstr; | ||
301 | OSystem m_system; | ||
302 | |||
303 | QString m_sysverstr; | ||
304 | |||
305 | Transformation m_rotation; | ||
306 | ODirection m_direction; | ||
307 | |||
308 | QValueList <ODeviceButton> *m_buttons; | ||
309 | uint m_holdtime; | ||
310 | QStrList *m_cpu_frequencies; | ||
311 | }; | ||
312 | |||
313 | } | ||
314 | |||
315 | static inline bool isQWS() | ||
316 | { | ||
317 | return qApp ? ( qApp->type() == QApplication::GuiServer ) : false; | ||
318 | } | ||
319 | |||
320 | static QCString makeChannel ( const char *str ) | ||
321 | { | ||
322 | if ( str && !::strchr ( str, '/' )) | ||
323 | return QCString ( "QPE/Application/" ) + str; | ||
324 | else | ||
325 | return str; | ||
326 | } | ||
327 | |||
328 | #endif | ||
329 | |||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include "odevice.h" | ||
31 | |||
32 | /* QT */ | ||
33 | #include <qapplication.h> | ||
34 | #include <qfile.h> | ||
35 | #include <qtextstream.h> | ||
36 | #include <qwindowsystem_qws.h> | ||
37 | |||
38 | /* OPIE */ | ||
39 | #include <qpe/config.h> | ||
40 | #include <qpe/resource.h> | ||
41 | #include <qpe/sound.h> | ||
42 | #include <qpe/qcopenvelope_qws.h> | ||
43 | |||
44 | /* STD */ | ||
45 | #include <fcntl.h> | ||
46 | #include <math.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <signal.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/time.h> | ||
51 | #include <unistd.h> | ||
52 | #ifndef QT_NO_SOUND | ||
53 | #include <linux/soundcard.h> | ||
54 | #endif | ||
55 | |||
56 | #ifndef ARRAY_SIZE | ||
57 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
58 | #endif | ||
59 | |||
60 | // _IO and friends are only defined in kernel headers ... | ||
61 | |||
62 | #define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) | ||
63 | |||
64 | #define OD_IO(type,number) OD_IOC(0,type,number,0) | ||
65 | #define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) | ||
66 | #define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) | ||
67 | #define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) | ||
68 | |||
69 | typedef struct { | ||
70 | unsigned char OffOnBlink; /* 0=off 1=on 2=Blink */ | ||
71 | unsigned char TotalTime; /* Units of 5 seconds */ | ||
72 | unsigned char OnTime; /* units of 100m/s */ | ||
73 | unsigned char OffTime; /* units of 100m/s */ | ||
74 | } LED_IN; | ||
75 | |||
76 | typedef struct { | ||
77 | unsigned char mode; | ||
78 | unsigned char pwr; | ||
79 | unsigned char brightness; | ||
80 | } FLITE_IN; | ||
81 | |||
82 | #define LED_ON OD_IOW( 'f', 5, LED_IN ) | ||
83 | #define FLITE_ON OD_IOW( 'f', 7, FLITE_IN ) | ||
84 | |||
85 | using namespace Opie; | ||
86 | |||
87 | class iPAQ : public ODevice, public QWSServer::KeyboardFilter | ||
88 | { | ||
89 | |||
90 | protected: | ||
91 | virtual void init(); | ||
92 | virtual void initButtons(); | ||
93 | |||
94 | public: | ||
95 | virtual bool setSoftSuspend( bool soft ); | ||
96 | |||
97 | virtual bool setDisplayBrightness( int b ); | ||
98 | virtual int displayBrightnessResolution() const; | ||
99 | |||
100 | virtual void alarmSound(); | ||
101 | |||
102 | virtual QValueList <OLed> ledList() const; | ||
103 | virtual QValueList <OLedState> ledStateList( OLed led ) const; | ||
104 | virtual OLedState ledState( OLed led ) const; | ||
105 | virtual bool setLedState( OLed led, OLedState st ); | ||
106 | |||
107 | virtual bool hasLightSensor() const; | ||
108 | virtual int readLightSensor(); | ||
109 | virtual int lightSensorResolution() const; | ||
110 | |||
111 | protected: | ||
112 | virtual bool filter( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); | ||
113 | virtual void timerEvent( QTimerEvent *te ); | ||
114 | |||
115 | int m_power_timer; | ||
116 | |||
117 | OLedState m_leds [2]; | ||
118 | }; | ||
119 | |||
120 | struct i_button { | ||
121 | uint model; | ||
122 | Qt::Key code; | ||
123 | char *utext; | ||
124 | char *pix; | ||
125 | char *fpressedservice; | ||
126 | char *fpressedaction; | ||
127 | char *fheldservice; | ||
128 | char *fheldaction; | ||
129 | } ipaq_buttons [] = { | ||
130 | { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, | ||
131 | Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), | ||
132 | "devicebuttons/ipaq_calendar", | ||
133 | "datebook", "nextView()", | ||
134 | "today", "raise()" }, | ||
135 | { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, | ||
136 | Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), | ||
137 | "devicebuttons/ipaq_contact", | ||
138 | "addressbook", "raise()", | ||
139 | "addressbook", "beamBusinessCard()" }, | ||
140 | { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx, | ||
141 | Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), | ||
142 | "devicebuttons/ipaq_menu", | ||
143 | "QPE/TaskBar", "toggleMenu()", | ||
144 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
145 | { Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, | ||
146 | Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), | ||
147 | "devicebuttons/ipaq_mail", | ||
148 | "mail", "raise()", | ||
149 | "mail", "newMail()" }, | ||
150 | { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, | ||
151 | Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), | ||
152 | "devicebuttons/ipaq_home", | ||
153 | "QPE/Launcher", "home()", | ||
154 | "buttonsettings", "raise()" }, | ||
155 | { Model_iPAQ_H31xx | Model_iPAQ_H36xx | Model_iPAQ_H37xx | Model_iPAQ_H38xx | Model_iPAQ_H39xx | Model_iPAQ_H5xxx, | ||
156 | Qt::Key_F24, QT_TRANSLATE_NOOP("Button", "Record Button"), | ||
157 | "devicebuttons/ipaq_record", | ||
158 | "QPE/VMemo", "toggleRecord()", | ||
159 | "sound", "raise()" }, | ||
160 | }; | ||
161 | |||
162 | void iPAQ::init() | ||
163 | { | ||
164 | d->m_vendorstr = "HP"; | ||
165 | d->m_vendor = Vendor_HP; | ||
166 | |||
167 | QFile f ( "/proc/hal/model" ); | ||
168 | |||
169 | if ( f. open ( IO_ReadOnly )) { | ||
170 | QTextStream ts ( &f ); | ||
171 | |||
172 | d->m_modelstr = "H" + ts. readLine(); | ||
173 | |||
174 | if ( d->m_modelstr == "H3100" ) | ||
175 | d->m_model = Model_iPAQ_H31xx; | ||
176 | else if ( d->m_modelstr == "H3600" ) | ||
177 | d->m_model = Model_iPAQ_H36xx; | ||
178 | else if ( d->m_modelstr == "H3700" ) | ||
179 | d->m_model = Model_iPAQ_H37xx; | ||
180 | else if ( d->m_modelstr == "H3800" ) | ||
181 | d->m_model = Model_iPAQ_H38xx; | ||
182 | else if ( d->m_modelstr == "H3900" ) | ||
183 | d->m_model = Model_iPAQ_H39xx; | ||
184 | else if ( d->m_modelstr == "H5400" ) | ||
185 | d->m_model = Model_iPAQ_H5xxx; | ||
186 | else | ||
187 | d->m_model = Model_Unknown; | ||
188 | |||
189 | f. close(); | ||
190 | } | ||
191 | |||
192 | switch ( d->m_model ) { | ||
193 | case Model_iPAQ_H31xx: | ||
194 | case Model_iPAQ_H38xx: | ||
195 | d->m_rotation = Rot90; | ||
196 | break; | ||
197 | case Model_iPAQ_H36xx: | ||
198 | case Model_iPAQ_H37xx: | ||
199 | case Model_iPAQ_H39xx: | ||
200 | |||
201 | default: | ||
202 | d->m_rotation = Rot270; | ||
203 | break; | ||
204 | case Model_iPAQ_H5xxx: | ||
205 | d->m_rotation = Rot0; | ||
206 | } | ||
207 | |||
208 | f. setName ( "/etc/familiar-version" ); | ||
209 | if ( f. open ( IO_ReadOnly )) { | ||
210 | d->m_systemstr = "Familiar"; | ||
211 | d->m_system = System_Familiar; | ||
212 | |||
213 | QTextStream ts ( &f ); | ||
214 | d->m_sysverstr = ts. readLine(). mid ( 10 ); | ||
215 | |||
216 | f. close(); | ||
217 | } else { | ||
218 | f. setName ( "/etc/oz_version" ); | ||
219 | |||
220 | if ( f. open ( IO_ReadOnly )) { | ||
221 | d->m_systemstr = "OpenEmbedded/iPaq"; | ||
222 | d->m_system = System_Familiar; | ||
223 | |||
224 | QTextStream ts ( &f ); | ||
225 | ts.setDevice ( &f ); | ||
226 | d->m_sysverstr = ts. readLine(); | ||
227 | f. close(); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | m_leds [0] = m_leds [1] = Led_Off; | ||
232 | |||
233 | m_power_timer = 0; | ||
234 | |||
235 | } | ||
236 | |||
237 | void iPAQ::initButtons() | ||
238 | { | ||
239 | if ( d->m_buttons ) | ||
240 | return; | ||
241 | |||
242 | if ( isQWS( ) ) | ||
243 | QWSServer::setKeyboardFilter ( this ); | ||
244 | |||
245 | d->m_buttons = new QValueList <ODeviceButton>; | ||
246 | |||
247 | for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) { | ||
248 | i_button *ib = ipaq_buttons + i; | ||
249 | ODeviceButton b; | ||
250 | |||
251 | if (( ib->model & d->m_model ) == d->m_model ) { | ||
252 | b. setKeycode ( ib->code ); | ||
253 | b. setUserText ( QObject::tr ( "Button", ib->utext )); | ||
254 | b. setPixmap ( Resource::loadPixmap ( ib->pix )); | ||
255 | b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib->fpressedservice ), ib->fpressedaction )); | ||
256 | b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib->fheldservice ), ib->fheldaction )); | ||
257 | |||
258 | d->m_buttons->append ( b ); | ||
259 | } | ||
260 | } | ||
261 | reloadButtonMapping(); | ||
262 | |||
263 | QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); | ||
264 | connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); | ||
265 | } | ||
266 | |||
267 | QValueList <OLed> iPAQ::ledList() const | ||
268 | { | ||
269 | QValueList <OLed> vl; | ||
270 | vl << Led_Power; | ||
271 | |||
272 | if ( d->m_model == Model_iPAQ_H38xx ) | ||
273 | vl << Led_BlueTooth; | ||
274 | return vl; | ||
275 | } | ||
276 | |||
277 | QValueList <OLedState> iPAQ::ledStateList ( OLed l ) const | ||
278 | { | ||
279 | QValueList <OLedState> vl; | ||
280 | |||
281 | if ( l == Led_Power ) | ||
282 | vl << Led_Off << Led_On << Led_BlinkSlow << Led_BlinkFast; | ||
283 | else if ( l == Led_BlueTooth && d->m_model == Model_iPAQ_H38xx ) | ||
284 | vl << Led_Off; // << Led_On << ??? | ||
285 | |||
286 | return vl; | ||
287 | } | ||
288 | |||
289 | OLedState iPAQ::ledState ( OLed l ) const | ||
290 | { | ||
291 | switch ( l ) { | ||
292 | case Led_Power: | ||
293 | return m_leds [0]; | ||
294 | case Led_BlueTooth: | ||
295 | return m_leds [1]; | ||
296 | default: | ||
297 | return Led_Off; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | bool iPAQ::setLedState ( OLed l, OLedState st ) | ||
302 | { | ||
303 | static int fd = ::open ( "/dev/touchscreen/0", O_RDWR | O_NONBLOCK ); | ||
304 | |||
305 | if ( l == Led_Power ) { | ||
306 | if ( fd >= 0 ) { | ||
307 | LED_IN leds; | ||
308 | ::memset ( &leds, 0, sizeof( leds )); | ||
309 | leds. TotalTime = 0; | ||
310 | leds. OnTime = 0; | ||
311 | leds. OffTime = 1; | ||
312 | leds. OffOnBlink = 2; | ||
313 | |||
314 | switch ( st ) { | ||
315 | case Led_Off : leds. OffOnBlink = 0; break; | ||
316 | case Led_On : leds. OffOnBlink = 1; break; | ||
317 | case Led_BlinkSlow: leds. OnTime = 10; leds. OffTime = 10; break; | ||
318 | case Led_BlinkFast: leds. OnTime = 5; leds. OffTime = 5; break; | ||
319 | } | ||
320 | |||
321 | if ( ::ioctl ( fd, LED_ON, &leds ) >= 0 ) { | ||
322 | m_leds [0] = st; | ||
323 | return true; | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | return false; | ||
328 | } | ||
329 | |||
330 | |||
331 | bool iPAQ::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat ) | ||
332 | { | ||
333 | int newkeycode = keycode; | ||
334 | |||
335 | switch ( keycode ) { | ||
336 | // H38xx/H39xx have no "Q" key anymore - this is now the Mail key | ||
337 | case HardKey_Menu: { | ||
338 | if (( d->m_model == Model_iPAQ_H38xx ) || | ||
339 | ( d->m_model == Model_iPAQ_H39xx ) || | ||
340 | ( d->m_model == Model_iPAQ_H5xxx)) { | ||
341 | newkeycode = HardKey_Mail; | ||
342 | } | ||
343 | break; | ||
344 | } | ||
345 | |||
346 | // Rotate cursor keys 180° | ||
347 | case Key_Left : | ||
348 | case Key_Right: | ||
349 | case Key_Up : | ||
350 | case Key_Down : { | ||
351 | if (( d->m_model == Model_iPAQ_H31xx ) || | ||
352 | ( d->m_model == Model_iPAQ_H38xx )) { | ||
353 | newkeycode = Key_Left + ( keycode - Key_Left + 2 ) % 4; | ||
354 | } | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | // map Power Button short/long press to F34/F35 | ||
359 | case Key_SysReq: { | ||
360 | if ( isPress ) { | ||
361 | if ( m_power_timer ) | ||
362 | killTimer ( m_power_timer ); | ||
363 | m_power_timer = startTimer ( 500 ); | ||
364 | } | ||
365 | else if ( m_power_timer ) { | ||
366 | killTimer ( m_power_timer ); | ||
367 | m_power_timer = 0; | ||
368 | QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, true, false ); | ||
369 | QWSServer::sendKeyEvent ( -1, HardKey_Suspend, 0, false, false ); | ||
370 | } | ||
371 | newkeycode = Key_unknown; | ||
372 | break; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | if ( newkeycode != keycode ) { | ||
377 | if ( newkeycode != Key_unknown ) | ||
378 | QWSServer::sendKeyEvent ( -1, newkeycode, modifiers, isPress, autoRepeat ); | ||
379 | return true; | ||
380 | } | ||
381 | else | ||
382 | return false; | ||
383 | } | ||
384 | |||
385 | void iPAQ::timerEvent ( QTimerEvent * ) | ||
386 | { | ||
387 | killTimer ( m_power_timer ); | ||
388 | m_power_timer = 0; | ||
389 | QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false ); | ||
390 | QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false ); | ||
391 | } | ||
392 | |||
393 | |||
394 | void iPAQ::alarmSound() | ||
395 | { | ||
396 | #ifndef QT_NO_SOUND | ||
397 | static Sound snd ( "alarm" ); | ||
398 | int fd; | ||
399 | int vol; | ||
400 | bool vol_reset = false; | ||
401 | |||
402 | if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { | ||
403 | if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { | ||
404 | Config cfg ( "qpe" ); | ||
405 | cfg. setGroup ( "Volume" ); | ||
406 | |||
407 | int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); | ||
408 | if ( volalarm < 0 ) | ||
409 | volalarm = 0; | ||
410 | else if ( volalarm > 100 ) | ||
411 | volalarm = 100; | ||
412 | volalarm |= ( volalarm << 8 ); | ||
413 | |||
414 | if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) | ||
415 | vol_reset = true; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | snd. play(); | ||
420 | while ( !snd. isFinished()) | ||
421 | qApp->processEvents(); | ||
422 | |||
423 | if ( fd >= 0 ) { | ||
424 | if ( vol_reset ) | ||
425 | ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); | ||
426 | ::close ( fd ); | ||
427 | } | ||
428 | #endif | ||
429 | } | ||
430 | |||
431 | |||
432 | bool iPAQ::setSoftSuspend ( bool soft ) | ||
433 | { | ||
434 | bool res = false; | ||
435 | int fd; | ||
436 | |||
437 | if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) { | ||
438 | if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 ) | ||
439 | res = true; | ||
440 | else | ||
441 | ::perror ( "write to /proc/sys/ts/suspend_button_mode" ); | ||
442 | |||
443 | ::close ( fd ); | ||
444 | } | ||
445 | else | ||
446 | ::perror ( "/proc/sys/ts/suspend_button_mode" ); | ||
447 | |||
448 | return res; | ||
449 | } | ||
450 | |||
451 | |||
452 | bool iPAQ::setDisplayBrightness ( int bright ) | ||
453 | { | ||
454 | bool res = false; | ||
455 | int fd; | ||
456 | |||
457 | if ( bright > 255 ) | ||
458 | bright = 255; | ||
459 | if ( bright < 0 ) | ||
460 | bright = 0; | ||
461 | |||
462 | if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) { | ||
463 | FLITE_IN bl; | ||
464 | bl. mode = 1; | ||
465 | bl. pwr = bright ? 1 : 0; | ||
466 | bl. brightness = ( bright * ( displayBrightnessResolution() - 1 ) + 127 ) / 255; | ||
467 | res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 ); | ||
468 | ::close ( fd ); | ||
469 | } | ||
470 | return res; | ||
471 | } | ||
472 | |||
473 | int iPAQ::displayBrightnessResolution() const | ||
474 | { | ||
475 | switch ( model()) { | ||
476 | case Model_iPAQ_H31xx: | ||
477 | case Model_iPAQ_H36xx: | ||
478 | case Model_iPAQ_H37xx: | ||
479 | return 128; // really 256, but >128 could damage the LCD | ||
480 | |||
481 | case Model_iPAQ_H38xx: | ||
482 | case Model_iPAQ_H39xx: | ||
483 | return 64; | ||
484 | case Model_iPAQ_H5xxx: | ||
485 | return 255; | ||
486 | |||
487 | default: | ||
488 | return 2; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | |||
493 | bool iPAQ::hasLightSensor() const | ||
494 | { | ||
495 | return true; | ||
496 | } | ||
497 | |||
498 | int iPAQ::readLightSensor() | ||
499 | { | ||
500 | int fd; | ||
501 | int val = -1; | ||
502 | |||
503 | if (( fd = ::open ( "/proc/hal/light_sensor", O_RDONLY )) >= 0 ) { | ||
504 | char buffer [8]; | ||
505 | |||
506 | if ( ::read ( fd, buffer, 5 ) == 5 ) { | ||
507 | char *endptr; | ||
508 | |||
509 | buffer [4] = 0; | ||
510 | val = ::strtol ( buffer + 2, &endptr, 16 ); | ||
511 | |||
512 | if ( *endptr != 0 ) | ||
513 | val = -1; | ||
514 | } | ||
515 | ::close ( fd ); | ||
516 | } | ||
517 | |||
518 | return val; | ||
519 | } | ||
520 | |||
521 | int iPAQ::lightSensorResolution() const | ||
522 | { | ||
523 | return 256; | ||
524 | } | ||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include "odevice.h" | ||
31 | |||
32 | /* QT */ | ||
33 | #include <qapplication.h> | ||
34 | #include <qfile.h> | ||
35 | #include <qtextstream.h> | ||
36 | #include <qwindowsystem_qws.h> | ||
37 | |||
38 | /* OPIE */ | ||
39 | #include <qpe/config.h> | ||
40 | #include <qpe/resource.h> | ||
41 | #include <qpe/sound.h> | ||
42 | #include <qpe/qcopenvelope_qws.h> | ||
43 | |||
44 | /* STD */ | ||
45 | #include <fcntl.h> | ||
46 | #include <math.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <signal.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/time.h> | ||
51 | #include <unistd.h> | ||
52 | #ifndef QT_NO_SOUND | ||
53 | #include <linux/soundcard.h> | ||
54 | #endif | ||
55 | |||
56 | #ifndef ARRAY_SIZE | ||
57 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
58 | #endif | ||
59 | |||
60 | // _IO and friends are only defined in kernel headers ... | ||
61 | |||
62 | #define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) | ||
63 | |||
64 | #define OD_IO(type,number) OD_IOC(0,type,number,0) | ||
65 | #define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) | ||
66 | #define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) | ||
67 | #define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) | ||
68 | |||
69 | typedef struct { | ||
70 | unsigned char OffOnBlink; /* 0=off 1=on 2=Blink */ | ||
71 | unsigned char TotalTime; /* Units of 5 seconds */ | ||
72 | unsigned char OnTime; /* units of 100m/s */ | ||
73 | unsigned char OffTime; /* units of 100m/s */ | ||
74 | } LED_IN; | ||
75 | |||
76 | typedef struct { | ||
77 | unsigned char mode; | ||
78 | unsigned char pwr; | ||
79 | unsigned char brightness; | ||
80 | } FLITE_IN; | ||
81 | |||
82 | #define LED_ON OD_IOW( 'f', 5, LED_IN ) | ||
83 | #define FLITE_ON OD_IOW( 'f', 7, FLITE_IN ) | ||
84 | |||
85 | using namespace Opie; | ||
86 | |||
87 | class Jornada : public ODevice | ||
88 | { | ||
89 | |||
90 | protected: | ||
91 | virtual void init(); | ||
92 | |||
93 | public: | ||
94 | virtual bool setSoftSuspend ( bool soft ); | ||
95 | virtual bool setDisplayBrightness ( int b ); | ||
96 | virtual int displayBrightnessResolution() const; | ||
97 | static bool isJornada(); | ||
98 | }; | ||
99 | |||
100 | |||
101 | bool Jornada::isJornada() | ||
102 | { | ||
103 | QFile f( "/proc/cpuinfo" ); | ||
104 | if ( f. open ( IO_ReadOnly ) ) { | ||
105 | QTextStream ts ( &f ); | ||
106 | QString line; | ||
107 | while( line = ts. readLine() ) { | ||
108 | if ( line. left ( 8 ) == "Hardware" ) { | ||
109 | int loc = line. find ( ":" ); | ||
110 | if ( loc != -1 ) { | ||
111 | QString model = line.mid( loc + 2 ).simplifyWhiteSpace( ); | ||
112 | return ( model == "HP Jornada 56x" ); | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | return false; | ||
118 | } | ||
119 | |||
120 | void Jornada::init() | ||
121 | { | ||
122 | d->m_vendorstr = "HP"; | ||
123 | d->m_vendor = Vendor_HP; | ||
124 | d->m_modelstr = "Jornada 56x"; | ||
125 | d->m_model = Model_Jornada_56x; | ||
126 | d->m_systemstr = "Familiar"; | ||
127 | d->m_system = System_Familiar; | ||
128 | d->m_rotation = Rot0; | ||
129 | |||
130 | QFile f ( "/etc/familiar-version" ); | ||
131 | f. setName ( "/etc/familiar-version" ); | ||
132 | if ( f. open ( IO_ReadOnly )) { | ||
133 | |||
134 | QTextStream ts ( &f ); | ||
135 | d->m_sysverstr = ts. readLine(). mid ( 10 ); | ||
136 | |||
137 | f. close(); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | #if 0 | ||
142 | void Jornada::initButtons() | ||
143 | { | ||
144 | if ( d->m_buttons ) | ||
145 | return; | ||
146 | |||
147 | // Simulation uses iPAQ 3660 device buttons | ||
148 | |||
149 | qDebug ( "init Buttons" ); | ||
150 | d->m_buttons = new QValueList <ODeviceButton>; | ||
151 | |||
152 | for ( uint i = 0; i < ( sizeof( ipaq_buttons ) / sizeof( i_button )); i++ ) { | ||
153 | i_button *ib = ipaq_buttons + i; | ||
154 | ODeviceButton b; | ||
155 | |||
156 | if (( ib->model & Model_iPAQ_H36xx ) == Model_iPAQ_H36xx ) { | ||
157 | b. setKeycode ( ib->code ); | ||
158 | b. setUserText ( QObject::tr ( "Button", ib->utext )); | ||
159 | b. setPixmap ( Resource::loadPixmap ( ib->pix )); | ||
160 | b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( ib->fpressedservice ), ib->fpressedaction )); | ||
161 | b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( ib->fheldservice ), ib->fheldaction )); | ||
162 | d->m_buttons->append ( b ); | ||
163 | } | ||
164 | } | ||
165 | reloadButtonMapping(); | ||
166 | |||
167 | QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); | ||
168 | connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); | ||
169 | } | ||
170 | #endif | ||
171 | |||
172 | int Jornada::displayBrightnessResolution() const | ||
173 | { | ||
174 | } | ||
175 | |||
176 | bool Jornada::setDisplayBrightness( int bright ) | ||
177 | { | ||
178 | bool res = false; | ||
179 | int fd; | ||
180 | |||
181 | if ( bright > 255 ) | ||
182 | bright = 255; | ||
183 | if ( bright < 0 ) | ||
184 | bright = 0; | ||
185 | |||
186 | if (( fd = ::open ( "/dev/touchscreen/0", O_WRONLY )) >= 0 ) { | ||
187 | FLITE_IN bl; | ||
188 | bl. mode = 1; | ||
189 | bl. pwr = bright ? 1 : 0; | ||
190 | bl. brightness = ( bright * ( displayBrightnessResolution() - 1 ) + 127 ) / 255; | ||
191 | res = ( ::ioctl ( fd, FLITE_ON, &bl ) == 0 ); | ||
192 | ::close ( fd ); | ||
193 | } | ||
194 | return res; | ||
195 | } | ||
196 | |||
197 | bool Jornada::setSoftSuspend( bool soft ) | ||
198 | { | ||
199 | bool res = false; | ||
200 | int fd; | ||
201 | |||
202 | if (( fd = ::open ( "/proc/sys/ts/suspend_button_mode", O_WRONLY )) >= 0 ) { | ||
203 | if ( ::write ( fd, soft ? "1" : "0", 1 ) == 1 ) | ||
204 | res = true; | ||
205 | else | ||
206 | ::perror ( "write to /proc/sys/ts/suspend_button_mode" ); | ||
207 | |||
208 | ::close ( fd ); | ||
209 | } | ||
210 | else | ||
211 | ::perror ( "/proc/sys/ts/suspend_button_mode" ); | ||
212 | |||
213 | return res; | ||
214 | } | ||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include "odevice.h" | ||
31 | |||
32 | /* QT */ | ||
33 | #include <qapplication.h> | ||
34 | #include <qfile.h> | ||
35 | #include <qtextstream.h> | ||
36 | #include <qwindowsystem_qws.h> | ||
37 | |||
38 | /* OPIE */ | ||
39 | #include <qpe/config.h> | ||
40 | #include <qpe/resource.h> | ||
41 | #include <qpe/sound.h> | ||
42 | #include <qpe/qcopenvelope_qws.h> | ||
43 | |||
44 | /* STD */ | ||
45 | #include <fcntl.h> | ||
46 | #include <math.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <signal.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/time.h> | ||
51 | #include <unistd.h> | ||
52 | #ifndef QT_NO_SOUND | ||
53 | #include <linux/soundcard.h> | ||
54 | #endif | ||
55 | |||
56 | #ifndef ARRAY_SIZE | ||
57 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
58 | #endif | ||
59 | |||
60 | // _IO and friends are only defined in kernel headers ... | ||
61 | |||
62 | #define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) | ||
63 | |||
64 | #define OD_IO(type,number) OD_IOC(0,type,number,0) | ||
65 | #define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) | ||
66 | #define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) | ||
67 | #define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) | ||
68 | |||
69 | using namespace Opie; | ||
70 | |||
71 | class Ramses : public ODevice, public QWSServer::KeyboardFilter | ||
72 | { | ||
73 | protected: | ||
74 | virtual void init(); | ||
75 | |||
76 | public: | ||
77 | virtual bool setSoftSuspend( bool soft ); | ||
78 | virtual bool suspend(); | ||
79 | |||
80 | virtual bool setDisplayStatus( bool on ); | ||
81 | virtual bool setDisplayBrightness( int b ); | ||
82 | virtual int displayBrightnessResolution() const; | ||
83 | virtual bool setDisplayContrast( int b ); | ||
84 | virtual int displayContrastResolution() const; | ||
85 | |||
86 | protected: | ||
87 | virtual bool filter ( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); | ||
88 | virtual void timerEvent ( QTimerEvent *te ); | ||
89 | |||
90 | int m_power_timer; | ||
91 | }; | ||
92 | |||
93 | struct r_button { | ||
94 | uint model; | ||
95 | Qt::Key code; | ||
96 | char *utext; | ||
97 | char *pix; | ||
98 | char *fpressedservice; | ||
99 | char *fpressedaction; | ||
100 | char *fheldservice; | ||
101 | char *fheldaction; | ||
102 | } ramses_buttons [] = { | ||
103 | { Model_Ramses_MNCI, | ||
104 | Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), | ||
105 | "devicebuttons/z_menu", | ||
106 | "QPE/TaskBar", "toggleMenu()", | ||
107 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
108 | { Model_Ramses_MNCI, | ||
109 | Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), | ||
110 | "devicebuttons/ipaq_home", | ||
111 | "QPE/Launcher", "home()", | ||
112 | "buttonsettings", "raise()" }, | ||
113 | }; | ||
114 | |||
115 | void Ramses::init() | ||
116 | { | ||
117 | d->m_vendorstr = "M und N"; | ||
118 | d->m_vendor = Vendor_MundN; | ||
119 | |||
120 | QFile f("/proc/sys/board/ramses"); | ||
121 | |||
122 | d->m_modelstr = "Ramses"; | ||
123 | d->m_model = Model_Ramses_MNCI; | ||
124 | |||
125 | d->m_rotation = Rot0; | ||
126 | d->m_holdtime = 1000; | ||
127 | |||
128 | f.setName("/etc/oz_version"); | ||
129 | |||
130 | if (f.open(IO_ReadOnly)) { | ||
131 | d->m_systemstr = "OpenEmbedded/Ramses"; | ||
132 | d->m_system = System_OpenZaurus; | ||
133 | |||
134 | QTextStream ts(&f); | ||
135 | ts.setDevice(&f); | ||
136 | d->m_sysverstr = ts.readLine(); | ||
137 | f.close(); | ||
138 | } | ||
139 | |||
140 | m_power_timer = 0; | ||
141 | |||
142 | #ifdef QT_QWS_ALLOW_OVERCLOCK | ||
143 | #warning *** Overclocking enabled - this may fry your hardware - you have been warned *** | ||
144 | #define OC(x...) x | ||
145 | #else | ||
146 | #define OC(x...) | ||
147 | #endif | ||
148 | |||
149 | // This table is true for a Intel XScale PXA 255 | ||
150 | |||
151 | d->m_cpu_frequencies->append("99000"); // mem= 99, run= 99, turbo= 99, PXbus= 50 | ||
152 | OC(d->m_cpu_frequencies->append("118000"); ) // mem=118, run=118, turbo=118, PXbus= 59 OC'd mem | ||
153 | d->m_cpu_frequencies->append("199100"); // mem= 99, run=199, turbo=199, PXbus= 99 | ||
154 | OC(d->m_cpu_frequencies->append("236000"); ) // mem=118, run=236, turbo=236, PXbus=118 OC'd mem | ||
155 | d->m_cpu_frequencies->append("298600"); // mem= 99, run=199, turbo=298, PXbus= 99 | ||
156 | OC(d->m_cpu_frequencies->append("354000"); ) // mem=118, run=236, turbo=354, PXbus=118 OC'd mem | ||
157 | d->m_cpu_frequencies->append("398099"); // mem= 99, run=199, turbo=398, PXbus= 99 | ||
158 | d->m_cpu_frequencies->append("398100"); // mem= 99, run=398, turbo=398, PXbus=196 | ||
159 | OC(d->m_cpu_frequencies->append("471000"); ) // mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus | ||
160 | |||
161 | } | ||
162 | |||
163 | bool Ramses::filter(int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat) | ||
164 | { | ||
165 | Q_UNUSED( keycode ); | ||
166 | Q_UNUSED( modifiers ); | ||
167 | Q_UNUSED( isPress ); | ||
168 | Q_UNUSED( autoRepeat ); | ||
169 | return false; | ||
170 | } | ||
171 | |||
172 | void Ramses::timerEvent(QTimerEvent *) | ||
173 | { | ||
174 | killTimer(m_power_timer); | ||
175 | m_power_timer = 0; | ||
176 | QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, true, false); | ||
177 | QWSServer::sendKeyEvent(-1, HardKey_Backlight, 0, false, false); | ||
178 | } | ||
179 | |||
180 | |||
181 | bool Ramses::setSoftSuspend(bool soft) | ||
182 | { | ||
183 | qDebug("Ramses::setSoftSuspend(%d)", soft); | ||
184 | #if 0 | ||
185 | bool res = false; | ||
186 | int fd; | ||
187 | |||
188 | if (((fd = ::open("/dev/apm_bios", O_RDWR)) >= 0) || | ||
189 | ((fd = ::open("/dev/misc/apm_bios",O_RDWR)) >= 0)) { | ||
190 | |||
191 | int sources = ::ioctl(fd, APM_IOCGEVTSRC, 0); // get current event sources | ||
192 | |||
193 | if (sources >= 0) { | ||
194 | if (soft) | ||
195 | sources &= ~APM_EVT_POWER_BUTTON; | ||
196 | else | ||
197 | sources |= APM_EVT_POWER_BUTTON; | ||
198 | |||
199 | if (::ioctl(fd, APM_IOCSEVTSRC, sources) >= 0) // set new event sources | ||
200 | res = true; | ||
201 | else | ||
202 | perror("APM_IOCGEVTSRC"); | ||
203 | } | ||
204 | else | ||
205 | perror("APM_IOCGEVTSRC"); | ||
206 | |||
207 | ::close(fd); | ||
208 | } | ||
209 | else | ||
210 | perror("/dev/apm_bios or /dev/misc/apm_bios"); | ||
211 | |||
212 | return res; | ||
213 | #else | ||
214 | return true; | ||
215 | #endif | ||
216 | } | ||
217 | |||
218 | bool Ramses::suspend() | ||
219 | { | ||
220 | qDebug("Ramses::suspend"); | ||
221 | return false; | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * This sets the display on or off | ||
226 | */ | ||
227 | bool Ramses::setDisplayStatus(bool on) | ||
228 | { | ||
229 | qDebug("Ramses::setDisplayStatus(%d)", on); | ||
230 | #if 0 | ||
231 | bool res = false; | ||
232 | int fd; | ||
233 | |||
234 | if ((fd = ::open ("/dev/fb/0", O_RDWR)) >= 0) { | ||
235 | res = (::ioctl(fd, FBIOBLANK, on ? VESA_NO_BLANKING : VESA_POWERDOWN) == 0); | ||
236 | ::close(fd); | ||
237 | } | ||
238 | return res; | ||
239 | #else | ||
240 | return true; | ||
241 | #endif | ||
242 | } | ||
243 | |||
244 | |||
245 | /* | ||
246 | * We get something between 0..255 into us | ||
247 | */ | ||
248 | bool Ramses::setDisplayBrightness(int bright) | ||
249 | { | ||
250 | qDebug("Ramses::setDisplayBrightness(%d)", bright); | ||
251 | bool res = false; | ||
252 | int fd; | ||
253 | |||
254 | // pwm1 brighness: 20 steps 500..0 (dunkel->hell) | ||
255 | |||
256 | if (bright > 255 ) | ||
257 | bright = 255; | ||
258 | if (bright < 0) | ||
259 | bright = 0; | ||
260 | |||
261 | // Turn backlight completely off | ||
262 | if ((fd = ::open("/proc/sys/board/lcd_backlight", O_WRONLY)) >= 0) { | ||
263 | char writeCommand[10]; | ||
264 | const int count = sprintf(writeCommand, "%d\n", bright ? 1 : 0); | ||
265 | res = (::write(fd, writeCommand, count) != -1); | ||
266 | ::close(fd); | ||
267 | } | ||
268 | |||
269 | // scale backlight brightness to hardware | ||
270 | bright = 500-(bright * 500 / 255); | ||
271 | if ((fd = ::open("/proc/sys/board/pwm1", O_WRONLY)) >= 0) { | ||
272 | qDebug(" %d ->pwm1", bright); | ||
273 | char writeCommand[100]; | ||
274 | const int count = sprintf(writeCommand, "%d\n", bright); | ||
275 | res = (::write(fd, writeCommand, count) != -1); | ||
276 | ::close(fd); | ||
277 | } | ||
278 | return res; | ||
279 | } | ||
280 | |||
281 | |||
282 | int Ramses::displayBrightnessResolution() const | ||
283 | { | ||
284 | return 32; | ||
285 | } | ||
286 | |||
287 | bool Ramses::setDisplayContrast(int contr) | ||
288 | { | ||
289 | qDebug("Ramses::setDisplayContrast(%d)", contr); | ||
290 | bool res = false; | ||
291 | int fd; | ||
292 | |||
293 | // pwm0 contrast: 20 steps 79..90 (dunkel->hell) | ||
294 | |||
295 | if (contr > 255 ) | ||
296 | contr = 255; | ||
297 | if (contr < 0) | ||
298 | contr = 0; | ||
299 | contr = 90 - (contr * 20 / 255); | ||
300 | |||
301 | if ((fd = ::open("/proc/sys/board/pwm0", O_WRONLY)) >= 0) { | ||
302 | qDebug(" %d ->pwm0", contr); | ||
303 | char writeCommand[100]; | ||
304 | const int count = sprintf(writeCommand, "%d\n", contr); | ||
305 | res = (::write(fd, writeCommand, count) != -1); | ||
306 | res = true; | ||
307 | ::close(fd); | ||
308 | } | ||
309 | return res; | ||
310 | } | ||
311 | |||
312 | |||
313 | int Ramses::displayContrastResolution() const | ||
314 | { | ||
315 | return 20; | ||
316 | } | ||
317 | |||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include "odevice.h" | ||
31 | |||
32 | /* QT */ | ||
33 | #include <qapplication.h> | ||
34 | #include <qfile.h> | ||
35 | #include <qtextstream.h> | ||
36 | #include <qwindowsystem_qws.h> | ||
37 | |||
38 | /* OPIE */ | ||
39 | #include <qpe/config.h> | ||
40 | #include <qpe/resource.h> | ||
41 | #include <qpe/sound.h> | ||
42 | #include <qpe/qcopenvelope_qws.h> | ||
43 | |||
44 | /* STD */ | ||
45 | #include <fcntl.h> | ||
46 | #include <math.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <signal.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/time.h> | ||
51 | #include <unistd.h> | ||
52 | #ifndef QT_NO_SOUND | ||
53 | #include <linux/soundcard.h> | ||
54 | #endif | ||
55 | |||
56 | #ifndef ARRAY_SIZE | ||
57 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
58 | #endif | ||
59 | |||
60 | // _IO and friends are only defined in kernel headers ... | ||
61 | |||
62 | #define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) | ||
63 | |||
64 | #define OD_IO(type,number) OD_IOC(0,type,number,0) | ||
65 | #define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) | ||
66 | #define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) | ||
67 | #define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) | ||
68 | |||
69 | using namespace Opie; | ||
70 | |||
71 | class SIMpad : public ODevice, public QWSServer::KeyboardFilter | ||
72 | { | ||
73 | protected: | ||
74 | virtual void init(); | ||
75 | virtual void initButtons(); | ||
76 | |||
77 | public: | ||
78 | virtual bool setSoftSuspend( bool soft ); | ||
79 | virtual bool suspend(); | ||
80 | |||
81 | virtual bool setDisplayStatus( bool on ); | ||
82 | virtual bool setDisplayBrightness( int b ); | ||
83 | virtual int displayBrightnessResolution() const; | ||
84 | |||
85 | virtual void alarmSound(); | ||
86 | |||
87 | virtual QValueList <OLed> ledList() const; | ||
88 | virtual QValueList <OLedState> ledStateList( OLed led ) const; | ||
89 | virtual OLedState ledState( OLed led ) const; | ||
90 | virtual bool setLedState( OLed led, OLedState st ); | ||
91 | |||
92 | protected: | ||
93 | virtual bool filter( int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat ); | ||
94 | virtual void timerEvent( QTimerEvent *te ); | ||
95 | |||
96 | int m_power_timer; | ||
97 | |||
98 | OLedState m_leds [1]; | ||
99 | }; | ||
100 | |||
101 | struct s_button { | ||
102 | uint model; | ||
103 | Qt::Key code; | ||
104 | char *utext; | ||
105 | char *pix; | ||
106 | char *fpressedservice; | ||
107 | char *fpressedaction; | ||
108 | char *fheldservice; | ||
109 | char *fheldaction; | ||
110 | } simpad_buttons [] = { | ||
111 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
112 | Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Lower+Up"), | ||
113 | "devicebuttons/simpad_lower_up", | ||
114 | "datebook", "nextView()", | ||
115 | "today", "raise()" }, | ||
116 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
117 | Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Lower+Down"), | ||
118 | "devicebuttons/simpad_lower_down", | ||
119 | "addressbook", "raise()", | ||
120 | "addressbook", "beamBusinessCard()" }, | ||
121 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
122 | Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Lower+Right"), | ||
123 | "devicebuttons/simpad_lower_right", | ||
124 | "QPE/TaskBar", "toggleMenu()", | ||
125 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
126 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
127 | Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Lower+Left"), | ||
128 | "devicebuttons/simpad_lower_left", | ||
129 | "mail", "raise()", | ||
130 | "mail", "newMail()" }, | ||
131 | |||
132 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
133 | Qt::Key_F5, QT_TRANSLATE_NOOP("Button", "Upper+Up"), | ||
134 | "devicebuttons/simpad_upper_up", | ||
135 | "QPE/Launcher", "home()", | ||
136 | "buttonsettings", "raise()" }, | ||
137 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
138 | Qt::Key_F6, QT_TRANSLATE_NOOP("Button", "Upper+Down"), | ||
139 | "devicebuttons/simpad_upper_down", | ||
140 | "addressbook", "raise()", | ||
141 | "addressbook", "beamBusinessCard()" }, | ||
142 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
143 | Qt::Key_F7, QT_TRANSLATE_NOOP("Button", "Upper+Right"), | ||
144 | "devicebuttons/simpad_upper_right", | ||
145 | "QPE/TaskBar", "toggleMenu()", | ||
146 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
147 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
148 | Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Upper+Left"), | ||
149 | "devicebuttons/simpad_upper_left", | ||
150 | "QPE/Rotation", "flip()", | ||
151 | "QPE/Rotation", "flip()" }, | ||
152 | /* | ||
153 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
154 | Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"), | ||
155 | "devicebuttons/simpad_lower_upper", | ||
156 | "QPE/Launcher", "home()", | ||
157 | "buttonsettings", "raise()" }, | ||
158 | { Model_SIMpad_CL4 | Model_SIMpad_SL4 | Model_SIMpad_SLC | Model_SIMpad_TSinus, | ||
159 | Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Lower+Upper"), | ||
160 | "devicebuttons/simpad_upper_lower", | ||
161 | "QPE/Launcher", "home()", | ||
162 | "buttonsettings", "raise()" }, | ||
163 | */ | ||
164 | }; | ||
165 | |||
166 | void SIMpad::init() | ||
167 | { | ||
168 | d->m_vendorstr = "SIEMENS"; | ||
169 | d->m_vendor = Vendor_SIEMENS; | ||
170 | |||
171 | QFile f ( "/proc/hal/model" ); | ||
172 | |||
173 | //TODO Implement model checking | ||
174 | //FIXME For now we assume an SL4 | ||
175 | |||
176 | d->m_modelstr = "SL4"; | ||
177 | d->m_model = Model_SIMpad_SL4; | ||
178 | |||
179 | switch ( d->m_model ) { | ||
180 | default: | ||
181 | d->m_rotation = Rot0; | ||
182 | d->m_direction = CCW; | ||
183 | d->m_holdtime = 1000; // 1000ms | ||
184 | |||
185 | break; | ||
186 | } | ||
187 | |||
188 | f. setName ( "/etc/familiar-version" ); | ||
189 | if ( f. open ( IO_ReadOnly )) { | ||
190 | d->m_systemstr = "Familiar"; | ||
191 | d->m_system = System_Familiar; | ||
192 | |||
193 | QTextStream ts ( &f ); | ||
194 | d->m_sysverstr = ts. readLine(). mid ( 10 ); | ||
195 | |||
196 | f. close(); | ||
197 | } else { | ||
198 | f. setName ( "/etc/oz_version" ); | ||
199 | |||
200 | if ( f. open ( IO_ReadOnly )) { | ||
201 | d->m_systemstr = "OpenEmbedded/SIMpad"; | ||
202 | d->m_system = System_OpenZaurus; | ||
203 | |||
204 | QTextStream ts ( &f ); | ||
205 | ts.setDevice ( &f ); | ||
206 | d->m_sysverstr = ts. readLine(); | ||
207 | f. close(); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | m_leds [0] = m_leds [1] = Led_Off; | ||
212 | |||
213 | m_power_timer = 0; | ||
214 | |||
215 | } | ||
216 | |||
217 | void SIMpad::initButtons() | ||
218 | { | ||
219 | if ( d->m_buttons ) | ||
220 | return; | ||
221 | |||
222 | if ( isQWS( ) ) | ||
223 | QWSServer::setKeyboardFilter ( this ); | ||
224 | |||
225 | d->m_buttons = new QValueList <ODeviceButton>; | ||
226 | |||
227 | for ( uint i = 0; i < ( sizeof( simpad_buttons ) / sizeof( s_button )); i++ ) { | ||
228 | s_button *sb = simpad_buttons + i; | ||
229 | ODeviceButton b; | ||
230 | |||
231 | if (( sb->model & d->m_model ) == d->m_model ) { | ||
232 | b. setKeycode ( sb->code ); | ||
233 | b. setUserText ( QObject::tr ( "Button", sb->utext )); | ||
234 | b. setPixmap ( Resource::loadPixmap ( sb->pix )); | ||
235 | b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( sb->fpressedservice ), sb->fpressedaction )); | ||
236 | b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( sb->fheldservice ), sb->fheldaction )); | ||
237 | |||
238 | d->m_buttons->append ( b ); | ||
239 | } | ||
240 | } | ||
241 | reloadButtonMapping(); | ||
242 | |||
243 | QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); | ||
244 | connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); | ||
245 | } | ||
246 | |||
247 | // SIMpad boardcontrol register CS3 | ||
248 | #define SIMPAD_BOARDCONTROL "/proc/cs3" | ||
249 | #define SIMPAD_VCC_5V_EN 0x0001 // For 5V PCMCIA | ||
250 | #define SIMPAD_VCC_3V_EN 0x0002 // FOR 3.3V PCMCIA | ||
251 | #define SIMPAD_EN1 0x0004 // This is only for EPROM's | ||
252 | #define SIMPAD_EN0 0x0008 // Both should be enable for 3.3V or 5V | ||
253 | #define SIMPAD_DISPLAY_ON 0x0010 | ||
254 | #define SIMPAD_PCMCIA_BUFF_DIS 0x0020 | ||
255 | #define SIMPAD_MQ_RESET 0x0040 | ||
256 | #define SIMPAD_PCMCIA_RESET 0x0080 | ||
257 | #define SIMPAD_DECT_POWER_ON 0x0100 | ||
258 | #define SIMPAD_IRDA_SD 0x0200 // Shutdown for powersave | ||
259 | #define SIMPAD_RS232_ON 0x0400 | ||
260 | #define SIMPAD_SD_MEDIAQ 0x0800 // Shutdown for powersave | ||
261 | #define SIMPAD_LED2_ON 0x1000 | ||
262 | #define SIMPAD_IRDA_MODE 0x2000 // Fast/Slow IrDA mode | ||
263 | #define SIMPAD_ENABLE_5V 0x4000 // Enable 5V circuit | ||
264 | #define SIMPAD_RESET_SIMCARD 0x8000 | ||
265 | |||
266 | //SIMpad touchscreen backlight strength control | ||
267 | #define SIMPAD_BACKLIGHT_CONTROL "/proc/driver/mq200/registers/PWM_CONTROL" | ||
268 | #define SIMPAD_BACKLIGHT_MASK 0x00a10044 | ||
269 | |||
270 | QValueList <OLed> SIMpad::ledList() const | ||
271 | { | ||
272 | QValueList <OLed> vl; | ||
273 | vl << Led_Power; //FIXME which LED is LED2 ? The green one or the amber one? | ||
274 | //vl << Led_Mail; //TODO find out if LED1 is accessible anyway | ||
275 | return vl; | ||
276 | } | ||
277 | |||
278 | QValueList <OLedState> SIMpad::ledStateList ( OLed l ) const | ||
279 | { | ||
280 | QValueList <OLedState> vl; | ||
281 | |||
282 | if ( l == Led_Power ) //FIXME which LED is LED2 ? The green one or the amber one? | ||
283 | vl << Led_Off << Led_On; | ||
284 | //else if ( l == Led_Mail ) //TODO find out if LED1 is accessible anyway | ||
285 | //vl << Led_Off; | ||
286 | return vl; | ||
287 | } | ||
288 | |||
289 | OLedState SIMpad::ledState ( OLed l ) const | ||
290 | { | ||
291 | switch ( l ) { | ||
292 | case Led_Power: | ||
293 | return m_leds [0]; | ||
294 | //case Led_Mail: | ||
295 | //return m_leds [1]; | ||
296 | default: | ||
297 | return Led_Off; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | bool SIMpad::setLedState ( OLed l, OLedState st ) | ||
302 | { | ||
303 | #if 0 | ||
304 | static int fd = ::open ( SIMPAD_BOARDCONTROL, O_RDWR | O_NONBLOCK ); | ||
305 | |||
306 | /*TODO Implement this like that: | ||
307 | read from cs3 | ||
308 | && with SIMPAD_LED2_ON | ||
309 | write to cs3 */ | ||
310 | m_leds [0] = st; | ||
311 | return true; | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | |||
316 | #endif | ||
317 | return false; | ||
318 | } | ||
319 | |||
320 | |||
321 | bool SIMpad::filter ( int /*unicode*/, int keycode, int modifiers, bool isPress, bool autoRepeat ) | ||
322 | { | ||
323 | //TODO | ||
324 | return false; | ||
325 | } | ||
326 | |||
327 | void SIMpad::timerEvent ( QTimerEvent * ) | ||
328 | { | ||
329 | killTimer ( m_power_timer ); | ||
330 | m_power_timer = 0; | ||
331 | QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, true, false ); | ||
332 | QWSServer::sendKeyEvent ( -1, HardKey_Backlight, 0, false, false ); | ||
333 | } | ||
334 | |||
335 | |||
336 | void SIMpad::alarmSound() | ||
337 | { | ||
338 | #ifndef QT_NO_SOUND | ||
339 | static Sound snd ( "alarm" ); | ||
340 | int fd; | ||
341 | int vol; | ||
342 | bool vol_reset = false; | ||
343 | |||
344 | if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { | ||
345 | if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { | ||
346 | Config cfg ( "qpe" ); | ||
347 | cfg. setGroup ( "Volume" ); | ||
348 | |||
349 | int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); | ||
350 | if ( volalarm < 0 ) | ||
351 | volalarm = 0; | ||
352 | else if ( volalarm > 100 ) | ||
353 | volalarm = 100; | ||
354 | volalarm |= ( volalarm << 8 ); | ||
355 | |||
356 | if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) | ||
357 | vol_reset = true; | ||
358 | } | ||
359 | } | ||
360 | |||
361 | snd. play(); | ||
362 | while ( !snd. isFinished()) | ||
363 | qApp->processEvents(); | ||
364 | |||
365 | if ( fd >= 0 ) { | ||
366 | if ( vol_reset ) | ||
367 | ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); | ||
368 | ::close ( fd ); | ||
369 | } | ||
370 | #endif | ||
371 | } | ||
372 | |||
373 | |||
374 | bool SIMpad::suspend() // Must override because SIMpad does NOT have apm | ||
375 | { | ||
376 | qDebug( "ODevice for SIMpad: suspend()" ); | ||
377 | if ( !isQWS( ) ) // only qwsserver is allowed to suspend | ||
378 | return false; | ||
379 | |||
380 | bool res = false; | ||
381 | |||
382 | struct timeval tvs, tvn; | ||
383 | ::gettimeofday ( &tvs, 0 ); | ||
384 | |||
385 | ::sync(); // flush fs caches | ||
386 | res = ( ::system ( "cat /dev/fb/0 >/tmp/.buffer; echo > /proc/sys/pm/suspend; cat /tmp/.buffer >/dev/fb/0" ) == 0 ); //TODO make better :) | ||
387 | |||
388 | return res; | ||
389 | } | ||
390 | |||
391 | |||
392 | bool SIMpad::setSoftSuspend ( bool soft ) | ||
393 | { | ||
394 | qDebug( "ODevice for SIMpad: UNHANDLED setSoftSuspend(%s)", soft? "on" : "off" ); | ||
395 | return false; | ||
396 | } | ||
397 | |||
398 | |||
399 | bool SIMpad::setDisplayStatus ( bool on ) | ||
400 | { | ||
401 | qDebug( "ODevice for SIMpad: setDisplayStatus(%s)", on? "on" : "off" ); | ||
402 | |||
403 | bool res = false; | ||
404 | int fd; | ||
405 | |||
406 | QString cmdline = QString().sprintf( "echo %s > /proc/cs3", on ? "0xd41a" : "0xd40a" ); //TODO make better :) | ||
407 | |||
408 | res = ( ::system( (const char*) cmdline ) == 0 ); | ||
409 | |||
410 | return res; | ||
411 | } | ||
412 | |||
413 | |||
414 | bool SIMpad::setDisplayBrightness ( int bright ) | ||
415 | { | ||
416 | qDebug( "ODevice for SIMpad: setDisplayBrightness( %d )", bright ); | ||
417 | bool res = false; | ||
418 | int fd; | ||
419 | |||
420 | if ( bright > 255 ) | ||
421 | bright = 255; | ||
422 | if ( bright < 1 ) | ||
423 | bright = 0; | ||
424 | |||
425 | if (( fd = ::open ( SIMPAD_BACKLIGHT_CONTROL, O_WRONLY )) >= 0 ) { | ||
426 | int value = 255 - bright; | ||
427 | const int mask = SIMPAD_BACKLIGHT_MASK; | ||
428 | value = value << 8; | ||
429 | value += mask; | ||
430 | char writeCommand[100]; | ||
431 | const int count = sprintf( writeCommand, "0x%x\n", value ); | ||
432 | res = ( ::write ( fd, writeCommand, count ) != -1 ); | ||
433 | ::close ( fd ); | ||
434 | } | ||
435 | return res; | ||
436 | } | ||
437 | |||
438 | |||
439 | int SIMpad::displayBrightnessResolution() const | ||
440 | { | ||
441 | return 255; // All SIMpad models share the same display | ||
442 | } | ||
443 | |||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include "odevice.h" | ||
31 | |||
32 | /* QT */ | ||
33 | #include <qapplication.h> | ||
34 | #include <qfile.h> | ||
35 | #include <qtextstream.h> | ||
36 | #include <qwindowsystem_qws.h> | ||
37 | |||
38 | /* OPIE */ | ||
39 | #include <qpe/config.h> | ||
40 | #include <qpe/resource.h> | ||
41 | #include <qpe/sound.h> | ||
42 | #include <qpe/qcopenvelope_qws.h> | ||
43 | |||
44 | /* STD */ | ||
45 | #include <fcntl.h> | ||
46 | #include <math.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <signal.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/time.h> | ||
51 | #include <unistd.h> | ||
52 | #ifndef QT_NO_SOUND | ||
53 | #include <linux/soundcard.h> | ||
54 | #endif | ||
55 | |||
56 | #ifndef ARRAY_SIZE | ||
57 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
58 | #endif | ||
59 | |||
60 | // _IO and friends are only defined in kernel headers ... | ||
61 | |||
62 | #define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) | ||
63 | |||
64 | #define OD_IO(type,number) OD_IOC(0,type,number,0) | ||
65 | #define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) | ||
66 | #define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) | ||
67 | #define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) | ||
68 | |||
69 | using namespace Opie; | ||
70 | |||
71 | class Yopy : public ODevice | ||
72 | { | ||
73 | protected: | ||
74 | |||
75 | virtual void init(); | ||
76 | virtual void initButtons(); | ||
77 | |||
78 | public: | ||
79 | virtual bool suspend(); | ||
80 | |||
81 | virtual bool setDisplayBrightness ( int b ); | ||
82 | virtual int displayBrightnessResolution() const; | ||
83 | |||
84 | static bool isYopy(); | ||
85 | }; | ||
86 | |||
87 | struct yopy_button { | ||
88 | Qt::Key code; | ||
89 | char *utext; | ||
90 | char *pix; | ||
91 | char *fpressedservice; | ||
92 | char *fpressedaction; | ||
93 | char *fheldservice; | ||
94 | char *fheldaction; | ||
95 | } yopy_buttons [] = { | ||
96 | { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Action Button"), | ||
97 | "devicebuttons/yopy_action", | ||
98 | "datebook", "nextView()", | ||
99 | "today", "raise()" }, | ||
100 | { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "OK Button"), | ||
101 | "devicebuttons/yopy_ok", | ||
102 | "addressbook", "raise()", | ||
103 | "addressbook", "beamBusinessCard()" }, | ||
104 | { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "End Button"), | ||
105 | "devicebuttons/yopy_end", | ||
106 | "QPE/Launcher", "home()", | ||
107 | "buttonsettings", "raise()" }, | ||
108 | }; | ||
109 | |||
110 | bool Yopy::isYopy() | ||
111 | { | ||
112 | QFile f( "/proc/cpuinfo" ); | ||
113 | if ( f. open ( IO_ReadOnly ) ) { | ||
114 | QTextStream ts ( &f ); | ||
115 | QString line; | ||
116 | while( line = ts. readLine() ) { | ||
117 | if ( line. left ( 8 ) == "Hardware" ) { | ||
118 | int loc = line. find ( ":" ); | ||
119 | if ( loc != -1 ) { | ||
120 | QString model = | ||
121 | line. mid ( loc + 2 ). simplifyWhiteSpace( ); | ||
122 | return ( model == "Yopy" ); | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | return false; | ||
128 | } | ||
129 | |||
130 | void Yopy::init() | ||
131 | { | ||
132 | d->m_vendorstr = "G.Mate"; | ||
133 | d->m_vendor = Vendor_GMate; | ||
134 | d->m_modelstr = "Yopy3700"; | ||
135 | d->m_model = Model_Yopy_3700; | ||
136 | d->m_rotation = Rot0; | ||
137 | |||
138 | d->m_systemstr = "Linupy"; | ||
139 | d->m_system = System_Linupy; | ||
140 | |||
141 | QFile f ( "/etc/issue" ); | ||
142 | if ( f. open ( IO_ReadOnly )) { | ||
143 | QTextStream ts ( &f ); | ||
144 | ts.readLine(); | ||
145 | d->m_sysverstr = ts. readLine(); | ||
146 | f. close(); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | void Yopy::initButtons() | ||
151 | { | ||
152 | if ( d->m_buttons ) | ||
153 | return; | ||
154 | |||
155 | d->m_buttons = new QValueList <ODeviceButton>; | ||
156 | |||
157 | for (uint i = 0; i < ( sizeof( yopy_buttons ) / sizeof(yopy_button)); i++) { | ||
158 | |||
159 | yopy_button *ib = yopy_buttons + i; | ||
160 | |||
161 | ODeviceButton b; | ||
162 | |||
163 | b. setKeycode ( ib->code ); | ||
164 | b. setUserText ( QObject::tr ( "Button", ib->utext )); | ||
165 | b. setPixmap ( Resource::loadPixmap ( ib->pix )); | ||
166 | b. setFactoryPresetPressedAction | ||
167 | (OQCopMessage(makeChannel(ib->fpressedservice), ib->fpressedaction)); | ||
168 | b. setFactoryPresetHeldAction | ||
169 | (OQCopMessage(makeChannel(ib->fheldservice), ib->fheldaction)); | ||
170 | |||
171 | d->m_buttons->append ( b ); | ||
172 | } | ||
173 | reloadButtonMapping(); | ||
174 | |||
175 | QCopChannel *sysch = new QCopChannel("QPE/System", this); | ||
176 | connect(sysch, SIGNAL(received(const QCString &, const QByteArray & )), | ||
177 | this, SLOT(systemMessage(const QCString &, const QByteArray & ))); | ||
178 | } | ||
179 | |||
180 | bool Yopy::suspend() | ||
181 | { | ||
182 | /* Opie for Yopy does not implement its own power management at the | ||
183 | moment. The public version runs parallel to X, and relies on the | ||
184 | existing power management features. */ | ||
185 | return false; | ||
186 | } | ||
187 | |||
188 | bool Yopy::setDisplayBrightness(int bright) | ||
189 | { | ||
190 | /* The code here works, but is disabled as the current version runs | ||
191 | parallel to X, and relies on the existing backlight demon. */ | ||
192 | #if 0 | ||
193 | if ( QFile::exists("/proc/sys/pm/light") ) { | ||
194 | int fd = ::open("/proc/sys/pm/light", O_WRONLY); | ||
195 | if (fd >= 0 ) { | ||
196 | if (bright) | ||
197 | ::write(fd, "1\n", 2); | ||
198 | else | ||
199 | ::write(fd, "0\n", 2); | ||
200 | ::close(fd); | ||
201 | return true; | ||
202 | } | ||
203 | } | ||
204 | #endif | ||
205 | return false; | ||
206 | } | ||
207 | |||
208 | int Yopy::displayBrightnessResolution() const | ||
209 | { | ||
210 | return 2; | ||
211 | } | ||
212 | |||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include "odevice.h" | ||
31 | |||
32 | /* QT */ | ||
33 | #include <qapplication.h> | ||
34 | #include <qfile.h> | ||
35 | #include <qtextstream.h> | ||
36 | #include <qwindowsystem_qws.h> | ||
37 | |||
38 | /* OPIE */ | ||
39 | #include <qpe/config.h> | ||
40 | #include <qpe/resource.h> | ||
41 | #include <qpe/sound.h> | ||
42 | #include <qpe/qcopenvelope_qws.h> | ||
43 | |||
44 | /* STD */ | ||
45 | #include <fcntl.h> | ||
46 | #include <math.h> | ||
47 | #include <stdlib.h> | ||
48 | #include <signal.h> | ||
49 | #include <sys/ioctl.h> | ||
50 | #include <sys/time.h> | ||
51 | #include <unistd.h> | ||
52 | #ifndef QT_NO_SOUND | ||
53 | #include <linux/soundcard.h> | ||
54 | #endif | ||
55 | |||
56 | #ifndef ARRAY_SIZE | ||
57 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
58 | #endif | ||
59 | |||
60 | // _IO and friends are only defined in kernel headers ... | ||
61 | |||
62 | #define OD_IOC(dir,type,number,size) (( dir << 30 ) | ( type << 8 ) | ( number ) | ( size << 16 )) | ||
63 | |||
64 | #define OD_IO(type,number) OD_IOC(0,type,number,0) | ||
65 | #define OD_IOW(type,number,size) OD_IOC(1,type,number,sizeof(size)) | ||
66 | #define OD_IOR(type,number,size) OD_IOC(2,type,number,sizeof(size)) | ||
67 | #define OD_IORW(type,number,size) OD_IOC(3,type,number,sizeof(size)) | ||
68 | |||
69 | using namespace Opie; | ||
70 | |||
71 | class Zaurus : public ODevice | ||
72 | { | ||
73 | |||
74 | protected: | ||
75 | virtual void init(); | ||
76 | virtual void initButtons(); | ||
77 | |||
78 | public: | ||
79 | virtual bool setSoftSuspend ( bool soft ); | ||
80 | |||
81 | virtual bool setDisplayBrightness ( int b ); | ||
82 | virtual int displayBrightnessResolution() const; | ||
83 | |||
84 | virtual void alarmSound(); | ||
85 | virtual void keySound(); | ||
86 | virtual void touchSound(); | ||
87 | |||
88 | virtual QValueList <OLed> ledList() const; | ||
89 | virtual QValueList <OLedState> ledStateList ( OLed led ) const; | ||
90 | virtual OLedState ledState( OLed led ) const; | ||
91 | virtual bool setLedState( OLed led, OLedState st ); | ||
92 | |||
93 | virtual bool hasHingeSensor() const; | ||
94 | virtual OHingeStatus readHingeSensor(); | ||
95 | |||
96 | static bool isZaurus(); | ||
97 | |||
98 | virtual bool suspend(); | ||
99 | virtual Transformation rotation() const; | ||
100 | virtual ODirection direction() const; | ||
101 | |||
102 | protected: | ||
103 | virtual void buzzer ( int snd ); | ||
104 | |||
105 | OLedState m_leds [1]; | ||
106 | bool m_embedix; | ||
107 | }; | ||
108 | |||
109 | struct z_button { | ||
110 | Qt::Key code; | ||
111 | char *utext; | ||
112 | char *pix; | ||
113 | char *fpressedservice; | ||
114 | char *fpressedaction; | ||
115 | char *fheldservice; | ||
116 | char *fheldaction; | ||
117 | } z_buttons [] = { | ||
118 | { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), | ||
119 | "devicebuttons/z_calendar", | ||
120 | "datebook", "nextView()", | ||
121 | "today", "raise()" }, | ||
122 | { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), | ||
123 | "devicebuttons/z_contact", | ||
124 | "addressbook", "raise()", | ||
125 | "addressbook", "beamBusinessCard()" }, | ||
126 | { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), | ||
127 | "devicebuttons/z_home", | ||
128 | "QPE/Launcher", "home()", | ||
129 | "buttonsettings", "raise()" }, | ||
130 | { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), | ||
131 | "devicebuttons/z_menu", | ||
132 | "QPE/TaskBar", "toggleMenu()", | ||
133 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
134 | { Qt::Key_F13, QT_TRANSLATE_NOOP("Button", "Mail Button"), | ||
135 | "devicebuttons/z_mail", | ||
136 | "mail", "raise()", | ||
137 | "mail", "newMail()" }, | ||
138 | }; | ||
139 | |||
140 | struct z_button z_buttons_c700 [] = { | ||
141 | { Qt::Key_F9, QT_TRANSLATE_NOOP("Button", "Calendar Button"), | ||
142 | "devicebuttons/z_calendar", | ||
143 | "datebook", "nextView()", | ||
144 | "today", "raise()" }, | ||
145 | { Qt::Key_F10, QT_TRANSLATE_NOOP("Button", "Contacts Button"), | ||
146 | "devicebuttons/z_contact", | ||
147 | "addressbook", "raise()", | ||
148 | "addressbook", "beamBusinessCard()" }, | ||
149 | { Qt::Key_F12, QT_TRANSLATE_NOOP("Button", "Home Button"), | ||
150 | "devicebuttons/z_home", | ||
151 | "QPE/Launcher", "home()", | ||
152 | "buttonsettings", "raise()" }, | ||
153 | { Qt::Key_F11, QT_TRANSLATE_NOOP("Button", "Menu Button"), | ||
154 | "devicebuttons/z_menu", | ||
155 | "QPE/TaskBar", "toggleMenu()", | ||
156 | "QPE/TaskBar", "toggleStartMenu()" }, | ||
157 | { Qt::Key_F14, QT_TRANSLATE_NOOP("Button", "Display Rotate"), | ||
158 | "devicebuttons/z_hinge", | ||
159 | "QPE/Rotation", "rotateDefault()", | ||
160 | "QPE/Dummy", "doNothing()" }, | ||
161 | }; | ||
162 | |||
163 | // Check whether this device is the sharp zaurus.. | ||
164 | // FIXME This gets unnecessary complicated. We should think about splitting the Zaurus | ||
165 | // class up into individual classes. We need three classes | ||
166 | // | ||
167 | // Zaurus-Collie (SA-model w/ 320x240 lcd, for SL5500 and SL5000) | ||
168 | // Zaurus-Poodle (PXA-model w/ 320x240 lcd, for SL5600) | ||
169 | // Zaurus-Corgi (PXA-model w/ 640x480 lcd, for C700, C750, C760, and C860) | ||
170 | // | ||
171 | // Only question right now is: Do we really need to do it? Because as soon | ||
172 | // as the OpenZaurus kernel is ready, there will be a unified interface for all | ||
173 | // Zaurus models (concerning apm, backlight, buttons, etc.) | ||
174 | // | ||
175 | // Comments? - mickeyl. | ||
176 | |||
177 | bool Zaurus::isZaurus() | ||
178 | { | ||
179 | |||
180 | // If the special devices by embedix exist, it is quite simple: it is a Zaurus ! | ||
181 | if ( QFile::exists ( "/dev/sharp_buz" ) || QFile::exists ( "/dev/sharp_led" ) ){ | ||
182 | return true; | ||
183 | } | ||
184 | |||
185 | // On non-embedix kernels, we have to look closer. | ||
186 | bool is_zaurus = false; | ||
187 | QFile f ( "/proc/cpuinfo" ); | ||
188 | if ( f. open ( IO_ReadOnly ) ) { | ||
189 | QString model; | ||
190 | QFile f ( "/proc/cpuinfo" ); | ||
191 | |||
192 | QTextStream ts ( &f ); | ||
193 | QString line; | ||
194 | while( line = ts. readLine() ) { | ||
195 | if ( line. left ( 8 ) == "Hardware" ) | ||
196 | break; | ||
197 | } | ||
198 | int loc = line. find ( ":" ); | ||
199 | if ( loc != -1 ) | ||
200 | model = line. mid ( loc + 2 ). simplifyWhiteSpace( ); | ||
201 | |||
202 | if ( model == "Sharp-Collie" | ||
203 | || model == "Collie" | ||
204 | || model == "SHARP Corgi" | ||
205 | || model == "SHARP Shepherd" | ||
206 | || model == "SHARP Poodle" | ||
207 | || model == "SHARP Husky" | ||
208 | ) | ||
209 | is_zaurus = true; | ||
210 | |||
211 | } | ||
212 | return is_zaurus; | ||
213 | } | ||
214 | |||
215 | |||
216 | void Zaurus::init() | ||
217 | { | ||
218 | d->m_vendorstr = "Sharp"; | ||
219 | d->m_vendor = Vendor_Sharp; | ||
220 | m_embedix = true; // Not openzaurus means: It has an embedix kernel ! | ||
221 | |||
222 | // QFile f ( "/proc/filesystems" ); | ||
223 | QString model; | ||
224 | |||
225 | // It isn't a good idea to check the system configuration to | ||
226 | // detect the distribution ! | ||
227 | // Otherwise it may happen that any other distribution is detected as openzaurus, just | ||
228 | // because it uses a jffs2 filesystem.. | ||
229 | // (eilers) | ||
230 | // if ( f. open ( IO_ReadOnly ) && ( QTextStream ( &f ). read(). find ( "\tjffs2\n" ) >= 0 )) { | ||
231 | QFile f ("/etc/oz_version"); | ||
232 | if ( f.exists() ){ | ||
233 | d->m_vendorstr = "OpenZaurus Team"; | ||
234 | d->m_systemstr = "OpenZaurus"; | ||
235 | d->m_system = System_OpenZaurus; | ||
236 | |||
237 | if ( f. open ( IO_ReadOnly )) { | ||
238 | QTextStream ts ( &f ); | ||
239 | d->m_sysverstr = ts. readLine();//. mid ( 10 ); | ||
240 | f. close(); | ||
241 | } | ||
242 | |||
243 | // Openzaurus sometimes uses the embedix kernel! | ||
244 | // => Check whether this is an embedix kernel | ||
245 | FILE *uname = popen("uname -r", "r"); | ||
246 | QString line; | ||
247 | if ( f.open(IO_ReadOnly, uname) ) { | ||
248 | QTextStream ts ( &f ); | ||
249 | line = ts. readLine(); | ||
250 | int loc = line. find ( "embedix" ); | ||
251 | if ( loc != -1 ) | ||
252 | m_embedix = true; | ||
253 | else | ||
254 | m_embedix = false; | ||
255 | f. close(); | ||
256 | } | ||
257 | pclose(uname); | ||
258 | } | ||
259 | else { | ||
260 | d->m_systemstr = "Zaurus"; | ||
261 | d->m_system = System_Zaurus; | ||
262 | } | ||
263 | |||
264 | f. setName ( "/proc/cpuinfo" ); | ||
265 | if ( f. open ( IO_ReadOnly ) ) { | ||
266 | QTextStream ts ( &f ); | ||
267 | QString line; | ||
268 | while( line = ts. readLine() ) { | ||
269 | if ( line. left ( 8 ) == "Hardware" ) | ||
270 | break; | ||
271 | } | ||
272 | int loc = line. find ( ":" ); | ||
273 | if ( loc != -1 ) | ||
274 | model = line. mid ( loc + 2 ). simplifyWhiteSpace( ); | ||
275 | } | ||
276 | |||
277 | if ( model == "SHARP Corgi" ) { | ||
278 | d->m_model = Model_Zaurus_SLC7x0; | ||
279 | d->m_modelstr = "Zaurus SL-C700"; | ||
280 | } else if ( model == "SHARP Shepherd" ) { | ||
281 | d->m_model = Model_Zaurus_SLC7x0; | ||
282 | d->m_modelstr = "Zaurus SL-C750"; | ||
283 | } else if ( model == "SHARP Husky" ) { | ||
284 | d->m_model = Model_Zaurus_SLC7x0; | ||
285 | d->m_modelstr = "Zaurus SL-C760"; | ||
286 | } else if ( model == "SHARP Poodle" ) { | ||
287 | d->m_model = Model_Zaurus_SLB600; | ||
288 | d->m_modelstr = "Zaurus SL-B500 or SL-5600"; | ||
289 | } else if ( model == "Sharp-Collie" || model == "Collie" ) { | ||
290 | d->m_model = Model_Zaurus_SL5500; | ||
291 | d->m_modelstr = "Zaurus SL-5500 or SL-5000d"; | ||
292 | } else { | ||
293 | d->m_model = Model_Zaurus_SL5500; | ||
294 | d->m_modelstr = "Zaurus (Model unknown)"; | ||
295 | } | ||
296 | |||
297 | bool flipstate = false; | ||
298 | switch ( d->m_model ) { | ||
299 | case Model_Zaurus_SLA300: | ||
300 | d->m_rotation = Rot0; | ||
301 | break; | ||
302 | case Model_Zaurus_SLC7x0: | ||
303 | d->m_rotation = rotation(); | ||
304 | d->m_direction = direction(); | ||
305 | break; | ||
306 | case Model_Zaurus_SLB600: | ||
307 | case Model_Zaurus_SL5500: | ||
308 | case Model_Zaurus_SL5000: | ||
309 | default: | ||
310 | d->m_rotation = Rot270; | ||
311 | break; | ||
312 | } | ||
313 | m_leds [0] = Led_Off; | ||
314 | } | ||
315 | |||
316 | void Zaurus::initButtons() | ||
317 | { | ||
318 | if ( d->m_buttons ) | ||
319 | return; | ||
320 | |||
321 | d->m_buttons = new QValueList <ODeviceButton>; | ||
322 | |||
323 | struct z_button * pz_buttons; | ||
324 | int buttoncount; | ||
325 | switch ( d->m_model ) { | ||
326 | case Model_Zaurus_SLC7x0: | ||
327 | pz_buttons = z_buttons_c700; | ||
328 | buttoncount = ARRAY_SIZE(z_buttons_c700); | ||
329 | break; | ||
330 | default: | ||
331 | pz_buttons = z_buttons; | ||
332 | buttoncount = ARRAY_SIZE(z_buttons); | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | for ( int i = 0; i < buttoncount; i++ ) { | ||
337 | struct z_button *zb = pz_buttons + i; | ||
338 | ODeviceButton b; | ||
339 | |||
340 | b. setKeycode ( zb->code ); | ||
341 | b. setUserText ( QObject::tr ( "Button", zb->utext )); | ||
342 | b. setPixmap ( Resource::loadPixmap ( zb->pix )); | ||
343 | b. setFactoryPresetPressedAction ( OQCopMessage ( makeChannel ( zb->fpressedservice ), | ||
344 | zb->fpressedaction )); | ||
345 | b. setFactoryPresetHeldAction ( OQCopMessage ( makeChannel ( zb->fheldservice ), | ||
346 | zb->fheldaction )); | ||
347 | |||
348 | d->m_buttons->append ( b ); | ||
349 | } | ||
350 | |||
351 | reloadButtonMapping(); | ||
352 | |||
353 | QCopChannel *sysch = new QCopChannel ( "QPE/System", this ); | ||
354 | connect ( sysch, SIGNAL( received( const QCString &, const QByteArray & )), | ||
355 | this, SLOT( systemMessage ( const QCString &, const QByteArray & ))); | ||
356 | } | ||
357 | |||
358 | #include <unistd.h> | ||
359 | #include <fcntl.h> | ||
360 | #include <sys/ioctl.h> | ||
361 | |||
362 | //#include <asm/sharp_char.h> // including kernel headers is evil ... | ||
363 | |||
364 | #define SHARP_DEV_IOCTL_COMMAND_START 0x5680 | ||
365 | |||
366 | #defineSHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) | ||
367 | #define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START) | ||
368 | |||
369 | #define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */ | ||
370 | #define SHARP_BUZ_KEYSOUND 2 /* key sound */ | ||
371 | #define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */ | ||
372 | |||
373 | /* --- for SHARP_BUZZER device --- */ | ||
374 | |||
375 | //#defineSHARP_BUZZER_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) | ||
376 | //#define SHARP_BUZZER_MAKESOUND (SHARP_BUZZER_IOCTL_START) | ||
377 | |||
378 | #define SHARP_BUZZER_SETVOLUME (SHARP_BUZZER_IOCTL_START+1) | ||
379 | #define SHARP_BUZZER_GETVOLUME (SHARP_BUZZER_IOCTL_START+2) | ||
380 | #define SHARP_BUZZER_ISSUPPORTED (SHARP_BUZZER_IOCTL_START+3) | ||
381 | #define SHARP_BUZZER_SETMUTE (SHARP_BUZZER_IOCTL_START+4) | ||
382 | #define SHARP_BUZZER_STOPSOUND (SHARP_BUZZER_IOCTL_START+5) | ||
383 | |||
384 | //#define SHARP_BUZ_TOUCHSOUND 1 /* touch panel sound */ | ||
385 | //#define SHARP_BUZ_KEYSOUND 2 /* key sound */ | ||
386 | |||
387 | //#define SHARP_PDA_ILLCLICKSOUND 3 /* illegal click */ | ||
388 | //#define SHARP_PDA_WARNSOUND 4 /* warning occurred */ | ||
389 | //#define SHARP_PDA_ERRORSOUND 5 /* error occurred */ | ||
390 | //#define SHARP_PDA_CRITICALSOUND 6 /* critical error occurred */ | ||
391 | //#define SHARP_PDA_SYSSTARTSOUND 7 /* system start */ | ||
392 | //#define SHARP_PDA_SYSTEMENDSOUND 8 /* system shutdown */ | ||
393 | //#define SHARP_PDA_APPSTART 9 /* application start */ | ||
394 | //#define SHARP_PDA_APPQUIT 10 /* application ends */ | ||
395 | |||
396 | //#define SHARP_BUZ_SCHEDULE_ALARM 11 /* schedule alarm */ | ||
397 | //#define SHARP_BUZ_DAILY_ALARM 12 /* daily alarm */ | ||
398 | //#define SHARP_BUZ_GOT_PHONE_CALL 13 /* phone call sound */ | ||
399 | //#define SHARP_BUZ_GOT_MAIL 14 /* mail sound */ | ||
400 | // | ||
401 | |||
402 | #defineSHARP_LED_IOCTL_START (SHARP_DEV_IOCTL_COMMAND_START) | ||
403 | #define SHARP_LED_SETSTATUS (SHARP_LED_IOCTL_START+1) | ||
404 | |||
405 | #define SHARP_IOCTL_GET_ROTATION 0x413c | ||
406 | |||
407 | typedef struct sharp_led_status { | ||
408 | int which; /* select which LED status is wanted. */ | ||
409 | int status; /* set new led status if you call SHARP_LED_SETSTATUS */ | ||
410 | } sharp_led_status; | ||
411 | |||
412 | #define SHARP_LED_MAIL_EXISTS 9 /* mail status (exists or not) */ | ||
413 | |||
414 | #define LED_MAIL_NO_UNREAD_MAIL 0 /* for SHARP_LED_MAIL_EXISTS */ | ||
415 | #define LED_MAIL_NEWMAIL_EXISTS 1 /* for SHARP_LED_MAIL_EXISTS */ | ||
416 | #define LED_MAIL_UNREAD_MAIL_EX 2 /* for SHARP_LED_MAIL_EXISTS */ | ||
417 | |||
418 | // #include <asm/sharp_apm.h> // including kernel headers is evil ... | ||
419 | |||
420 | #define APM_IOCGEVTSRC OD_IOR( 'A', 203, int ) | ||
421 | #define APM_IOCSEVTSRC OD_IORW( 'A', 204, int ) | ||
422 | #define APM_EVT_POWER_BUTTON (1 << 0) | ||
423 | |||
424 | #define FL_IOCTL_STEP_CONTRAST 100 | ||
425 | |||
426 | |||
427 | void Zaurus::buzzer ( int sound ) | ||
428 | { | ||
429 | #ifndef QT_NO_SOUND | ||
430 | QString soundname; | ||
431 | |||
432 | // Not all devices have real sound | ||
433 | if ( d->m_model == Model_Zaurus_SLC7x0 | ||
434 | || d->m_model == Model_Zaurus_SLB600 ){ | ||
435 | |||
436 | switch ( sound ){ | ||
437 | case SHARP_BUZ_SCHEDULE_ALARM: | ||
438 | soundname = "alarm"; | ||
439 | break; | ||
440 | case SHARP_BUZ_TOUCHSOUND: | ||
441 | soundname = "touchsound"; | ||
442 | break; | ||
443 | case SHARP_BUZ_KEYSOUND: | ||
444 | soundname = "keysound"; | ||
445 | break; | ||
446 | default: | ||
447 | soundname = "alarm"; | ||
448 | |||
449 | } | ||
450 | } | ||
451 | |||
452 | // If a soundname is defined, we expect that this device has | ||
453 | // sound capabilities.. Otherwise we expect to have the buzzer | ||
454 | // device.. | ||
455 | if ( !soundname.isEmpty() ){ | ||
456 | int fd; | ||
457 | int vol; | ||
458 | bool vol_reset = false; | ||
459 | |||
460 | Sound snd ( soundname ); | ||
461 | |||
462 | if (( fd = ::open ( "/dev/sound/mixer", O_RDWR )) >= 0 ) { | ||
463 | if ( ::ioctl ( fd, MIXER_READ( 0 ), &vol ) >= 0 ) { | ||
464 | Config cfg ( "qpe" ); | ||
465 | cfg. setGroup ( "Volume" ); | ||
466 | |||
467 | int volalarm = cfg. readNumEntry ( "AlarmPercent", 50 ); | ||
468 | if ( volalarm < 0 ) | ||
469 | volalarm = 0; | ||
470 | else if ( volalarm > 100 ) | ||
471 | volalarm = 100; | ||
472 | volalarm |= ( volalarm << 8 ); | ||
473 | |||
474 | if ( ::ioctl ( fd, MIXER_WRITE( 0 ), &volalarm ) >= 0 ) | ||
475 | vol_reset = true; | ||
476 | } | ||
477 | } | ||
478 | |||
479 | snd. play(); | ||
480 | while ( !snd. isFinished()) | ||
481 | qApp->processEvents(); | ||
482 | |||
483 | if ( fd >= 0 ) { | ||
484 | if ( vol_reset ) | ||
485 | ::ioctl ( fd, MIXER_WRITE( 0 ), &vol ); | ||
486 | ::close ( fd ); | ||
487 | } | ||
488 | } else { | ||
489 | int fd = ::open ( "/dev/sharp_buz", O_WRONLY|O_NONBLOCK ); | ||
490 | |||
491 | if ( fd >= 0 ) { | ||
492 | ::ioctl ( fd, SHARP_BUZZER_MAKESOUND, sound ); | ||
493 | ::close ( fd ); | ||
494 | } | ||
495 | |||
496 | } | ||
497 | #endif | ||
498 | } | ||
499 | |||
500 | |||
501 | void Zaurus::alarmSound() | ||
502 | { | ||
503 | buzzer ( SHARP_BUZ_SCHEDULE_ALARM ); | ||
504 | } | ||
505 | |||
506 | void Zaurus::touchSound() | ||
507 | { | ||
508 | buzzer ( SHARP_BUZ_TOUCHSOUND ); | ||
509 | } | ||
510 | |||
511 | void Zaurus::keySound() | ||
512 | { | ||
513 | buzzer ( SHARP_BUZ_KEYSOUND ); | ||
514 | } | ||
515 | |||
516 | |||
517 | QValueList <OLed> Zaurus::ledList() const | ||
518 | { | ||
519 | QValueList <OLed> vl; | ||
520 | vl << Led_Mail; | ||
521 | return vl; | ||
522 | } | ||
523 | |||
524 | QValueList <OLedState> Zaurus::ledStateList ( OLed l ) const | ||
525 | { | ||
526 | QValueList <OLedState> vl; | ||
527 | |||
528 | if ( l == Led_Mail ) | ||
529 | vl << Led_Off << Led_On << Led_BlinkSlow; | ||
530 | return vl; | ||
531 | } | ||
532 | |||
533 | OLedState Zaurus::ledState ( OLed which ) const | ||
534 | { | ||
535 | if ( which == Led_Mail ) | ||
536 | return m_leds [0]; | ||
537 | else | ||
538 | return Led_Off; | ||
539 | } | ||
540 | |||
541 | bool Zaurus::setLedState ( OLed which, OLedState st ) | ||
542 | { | ||
543 | if (!m_embedix) // Currently not supported on non_embedix kernels | ||
544 | return false; | ||
545 | |||
546 | static int fd = ::open ( "/dev/sharp_led", O_RDWR|O_NONBLOCK ); | ||
547 | |||
548 | if ( which == Led_Mail ) { | ||
549 | if ( fd >= 0 ) { | ||
550 | struct sharp_led_status leds; | ||
551 | ::memset ( &leds, 0, sizeof( leds )); | ||
552 | leds. which = SHARP_LED_MAIL_EXISTS; | ||
553 | bool ok = true; | ||
554 | |||
555 | switch ( st ) { | ||
556 | case Led_Off : leds. status = LED_MAIL_NO_UNREAD_MAIL; break; | ||
557 | case Led_On : leds. status = LED_MAIL_NEWMAIL_EXISTS; break; | ||
558 | case Led_BlinkSlow: leds. status = LED_MAIL_UNREAD_MAIL_EX; break; | ||
559 | default : ok = false; | ||
560 | } | ||
561 | |||
562 | if ( ok && ( ::ioctl ( fd, SHARP_LED_SETSTATUS, &leds ) >= 0 )) { | ||
563 | m_leds [0] = st; | ||
564 | return true; | ||
565 | } | ||
566 | } | ||
567 | } | ||
568 | return false; | ||
569 | } | ||
570 | |||
571 | bool Zaurus::setSoftSuspend ( bool soft ) | ||
572 | { | ||
573 | if (!m_embedix) { | ||
574 | /* non-Embedix kernels dont have kernel autosuspend */ | ||
575 | return ODevice::setSoftSuspend( soft ); | ||
576 | } | ||
577 | |||
578 | bool res = false; | ||
579 | int fd; | ||
580 | |||
581 | if ((( fd = ::open ( "/dev/apm_bios", O_RDWR )) >= 0 ) || | ||
582 | (( fd = ::open ( "/dev/misc/apm_bios",O_RDWR )) >= 0 )) { | ||
583 | |||
584 | int sources = ::ioctl ( fd, APM_IOCGEVTSRC, 0 ); // get current event sources | ||
585 | |||
586 | if ( sources >= 0 ) { | ||
587 | if ( soft ) | ||
588 | sources &= ~APM_EVT_POWER_BUTTON; | ||
589 | else | ||
590 | sources |= APM_EVT_POWER_BUTTON; | ||
591 | |||
592 | if ( ::ioctl ( fd, APM_IOCSEVTSRC, sources ) >= 0 ) // set new event sources | ||
593 | res = true; | ||
594 | else | ||
595 | perror ( "APM_IOCGEVTSRC" ); | ||
596 | } | ||
597 | else | ||
598 | perror ( "APM_IOCGEVTSRC" ); | ||
599 | |||
600 | ::close ( fd ); | ||
601 | } | ||
602 | else | ||
603 | perror ( "/dev/apm_bios or /dev/misc/apm_bios" ); | ||
604 | |||
605 | return res; | ||
606 | } | ||
607 | |||
608 | |||
609 | bool Zaurus::setDisplayBrightness ( int bright ) | ||
610 | { | ||
611 | //qDebug( "Zaurus::setDisplayBrightness( %d )", bright ); | ||
612 | bool res = false; | ||
613 | int fd; | ||
614 | |||
615 | if ( bright > 255 ) bright = 255; | ||
616 | if ( bright < 0 ) bright = 0; | ||
617 | |||
618 | if ( m_embedix ) | ||
619 | { | ||
620 | if ( d->m_model == Model_Zaurus_SLC7x0 ) | ||
621 | { | ||
622 | //qDebug( "using special treatment for devices with the corgi backlight interface" ); | ||
623 | // special treatment for devices with the corgi backlight interface | ||
624 | if (( fd = ::open ( "/proc/driver/fl/corgi-bl", O_WRONLY )) >= 0 ) | ||
625 | { | ||
626 | int value = ( bright == 1 ) ? 1 : bright * ( 17.0 / 255.0 ); | ||
627 | char writeCommand[100]; | ||
628 | const int count = sprintf( writeCommand, "0x%x\n", value ); | ||
629 | res = ( ::write ( fd, writeCommand, count ) != -1 ); | ||
630 | ::close ( fd ); | ||
631 | } | ||
632 | return res; | ||
633 | } | ||
634 | else | ||
635 | { | ||
636 | // standard treatment for devices with the dumb embedix frontlight interface | ||
637 | if (( fd = ::open ( "/dev/fl", O_WRONLY )) >= 0 ) { | ||
638 | int bl = ( bright * 4 + 127 ) / 255; // only 4 steps on zaurus | ||
639 | if ( bright && !bl ) | ||
640 | bl = 1; | ||
641 | res = ( ::ioctl ( fd, FL_IOCTL_STEP_CONTRAST, bl ) == 0 ); | ||
642 | ::close ( fd ); | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | else | ||
647 | { | ||
648 | // special treatment for the OpenZaurus unified interface | ||
649 | #define FB_BACKLIGHT_SET_BRIGHTNESS _IOW('F', 1, u_int) /* set brightness */ | ||
650 | if (( fd = ::open ( "/dev/fb0", O_WRONLY )) >= 0 ) { | ||
651 | res = ( ::ioctl ( fd , FB_BACKLIGHT_SET_BRIGHTNESS, bright ) == 0 ); | ||
652 | ::close ( fd ); | ||
653 | } | ||
654 | } | ||
655 | return res; | ||
656 | } | ||
657 | |||
658 | bool Zaurus::suspend() | ||
659 | { | ||
660 | qDebug("ODevice::suspend"); | ||
661 | if ( !isQWS( ) ) // only qwsserver is allowed to suspend | ||
662 | return false; | ||
663 | |||
664 | if ( d->m_model == Model_Unknown ) // better don't suspend in qvfb / on unkown devices | ||
665 | return false; | ||
666 | |||
667 | bool res = false; | ||
668 | |||
669 | struct timeval tvs, tvn; | ||
670 | ::gettimeofday ( &tvs, 0 ); | ||
671 | |||
672 | ::sync(); // flush fs caches | ||
673 | res = ( ::system ( "apm --suspend" ) == 0 ); | ||
674 | |||
675 | // This is needed because the iPAQ apm implementation is asynchronous and we | ||
676 | // can not be sure when exactly the device is really suspended | ||
677 | // This can be deleted as soon as a stable familiar with a synchronous apm implementation exists. | ||
678 | |||
679 | if ( res ) { | ||
680 | do { // Yes, wait 15 seconds. This APM bug sucks big time. | ||
681 | ::usleep ( 200 * 1000 ); | ||
682 | ::gettimeofday ( &tvn, 0 ); | ||
683 | } while ((( tvn. tv_sec - tvs. tv_sec ) * 1000 + ( tvn. tv_usec - tvs. tv_usec ) / 1000 ) < 15000 ); | ||
684 | } | ||
685 | |||
686 | QCopEnvelope ( "QPE/Rotation", "rotateDefault()" ); | ||
687 | return res; | ||
688 | } | ||
689 | |||
690 | |||
691 | Transformation Zaurus::rotation() const | ||
692 | { | ||
693 | Transformation rot; | ||
694 | int handle = 0; | ||
695 | int retval = 0; | ||
696 | |||
697 | switch ( d->m_model ) { | ||
698 | case Model_Zaurus_SLC7x0: | ||
699 | handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); | ||
700 | if (handle == -1) { | ||
701 | return Rot270; | ||
702 | } else { | ||
703 | retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); | ||
704 | ::close (handle); | ||
705 | |||
706 | if (retval == 2 ) | ||
707 | rot = Rot0; | ||
708 | else | ||
709 | rot = Rot270; | ||
710 | } | ||
711 | break; | ||
712 | case Model_Zaurus_SLA300: | ||
713 | case Model_Zaurus_SLB600: | ||
714 | case Model_Zaurus_SL5500: | ||
715 | case Model_Zaurus_SL5000: | ||
716 | default: | ||
717 | rot = d->m_rotation; | ||
718 | break; | ||
719 | } | ||
720 | |||
721 | return rot; | ||
722 | } | ||
723 | ODirection Zaurus::direction() const | ||
724 | { | ||
725 | ODirection dir; | ||
726 | int handle = 0; | ||
727 | int retval = 0; | ||
728 | switch ( d->m_model ) { | ||
729 | case Model_Zaurus_SLC7x0: | ||
730 | handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); | ||
731 | if (handle == -1) { | ||
732 | dir = CW; | ||
733 | } else { | ||
734 | retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); | ||
735 | ::close (handle); | ||
736 | if (retval == 2 ) | ||
737 | dir = CCW; | ||
738 | else | ||
739 | dir = CW; | ||
740 | } | ||
741 | break; | ||
742 | case Model_Zaurus_SLA300: | ||
743 | case Model_Zaurus_SLB600: | ||
744 | case Model_Zaurus_SL5500: | ||
745 | case Model_Zaurus_SL5000: | ||
746 | default: | ||
747 | dir = d->m_direction; | ||
748 | break; | ||
749 | } | ||
750 | return dir; | ||
751 | |||
752 | } | ||
753 | |||
754 | int Zaurus::displayBrightnessResolution() const | ||
755 | { | ||
756 | if (m_embedix) | ||
757 | return d->m_model == Model_Zaurus_SLC7x0 ? 18 : 5; | ||
758 | else | ||
759 | return 256; | ||
760 | } | ||
761 | |||
762 | bool Zaurus::hasHingeSensor() const | ||
763 | { | ||
764 | return d->m_model == Model_Zaurus_SLC7x0; | ||
765 | } | ||
766 | |||
767 | OHingeStatus Zaurus::readHingeSensor() | ||
768 | { | ||
769 | int handle = ::open("/dev/apm_bios", O_RDWR|O_NONBLOCK); | ||
770 | if (handle == -1) | ||
771 | { | ||
772 | qWarning("Zaurus::readHingeSensor() - failed (%s)", "unknown reason" ); //FIXME: use strerror | ||
773 | return CASE_UNKNOWN; | ||
774 | } | ||
775 | else | ||
776 | { | ||
777 | int retval = ::ioctl(handle, SHARP_IOCTL_GET_ROTATION); | ||
778 | ::close (handle); | ||
779 | if ( retval == CASE_CLOSED || retval == CASE_PORTRAIT || retval == CASE_LANDSCAPE ) | ||
780 | { | ||
781 | qDebug( "Zaurus::readHingeSensor() - result = %d", retval ); | ||
782 | return static_cast<OHingeStatus>( retval ); | ||
783 | } | ||
784 | else | ||
785 | { | ||
786 | qWarning("Zaurus::readHingeSensor() - couldn't compute hinge status!" ); | ||
787 | return CASE_UNKNOWN; | ||
788 | } | ||
789 | } | ||
790 | } | ||
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 @@ | |||
1 | /* | ||
2 | This file is part of the Opie Project | ||
3 | Copyright (C) The Opie Team <opie-devel@handhelds.org> | ||
4 | =. | ||
5 | .=l. | ||
6 | .>+-= | ||
7 | _;:, .> :=|. This program is free software; you can | ||
8 | .> <`_, > . <= redistribute it and/or modify it under | ||
9 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | ||
10 | .="- .-=="i, .._ License as published by the Free Software | ||
11 | - . .-<_> .<> Foundation; either version 2 of the License, | ||
12 | ._= =} : or (at your option) any later version. | ||
13 | .%`+i> _;_. | ||
14 | .i_,=:_. -<s. This program is distributed in the hope that | ||
15 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | ||
16 | : .. .:, . . . without even the implied warranty of | ||
17 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | ||
18 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | ||
19 | ..}^=.= = ; Library General Public License for more | ||
20 | ++= -. .` .: details. | ||
21 | : = ...= . :.=- | ||
22 | -. .:....=;==+<; You should have received a copy of the GNU | ||
23 | -_. . . )=. = Library General Public License along with | ||
24 | -- :-=` this library; see the file COPYING.LIB. | ||
25 | If not, write to the Free Software Foundation, | ||
26 | Inc., 59 Temple Place - Suite 330, | ||
27 | Boston, MA 02111-1307, USA. | ||
28 | */ | ||
29 | |||
30 | #include <qpixmap.h> | ||
31 | #include <qstring.h> | ||
32 | |||
33 | #include <qpe/qcopenvelope_qws.h> | ||
34 | #include <opie2/odevicebutton.h> | ||
35 | |||
36 | using namespace Opie; | ||
37 | |||
38 | class OQCopMessageData | ||
39 | { | ||
40 | public: | ||
41 | QCString m_channel; | ||
42 | QCString m_message; | ||
43 | QByteArray m_data; | ||
44 | }; | ||
45 | |||
46 | |||
47 | OQCopMessage::OQCopMessage() | ||
48 | : d ( 0 ) | ||
49 | { | ||
50 | init ( QCString(), QCString(), QByteArray()); | ||
51 | } | ||
52 | |||
53 | OQCopMessage::OQCopMessage ( const OQCopMessage © ) | ||
54 | : d ( 0 ) | ||
55 | { | ||
56 | init ( copy. channel(), copy. message(), copy. data()); | ||
57 | } | ||
58 | |||
59 | OQCopMessage &OQCopMessage::operator = ( const OQCopMessage &assign ) | ||
60 | { | ||
61 | init ( assign. channel(), assign. message(), assign. data()); | ||
62 | return *this; | ||
63 | } | ||
64 | |||
65 | OQCopMessage::OQCopMessage ( const QCString &ch, const QCString &m, const QByteArray &arg ) | ||
66 | : d ( 0 ) | ||
67 | { | ||
68 | init ( ch, m, arg ); | ||
69 | } | ||
70 | |||
71 | void OQCopMessage::init ( const QCString &ch, const QCString &m, const QByteArray &arg ) | ||
72 | { | ||
73 | if ( !d ) | ||
74 | d = new OQCopMessageData(); | ||
75 | d->m_channel = ch; | ||
76 | d->m_message = m; | ||
77 | d->m_data = arg; | ||
78 | } | ||
79 | |||
80 | bool OQCopMessage::send() | ||
81 | { | ||
82 | if ( d->m_channel. isEmpty() || d->m_message. isEmpty() ) | ||
83 | return false; | ||
84 | |||
85 | QCopEnvelope e ( d->m_channel, d->m_message ); | ||
86 | |||
87 | if ( d->m_data. size()) | ||
88 | e. writeRawBytes ( d->m_data. data(), d->m_data. size()); | ||
89 | |||
90 | return true; | ||
91 | } | ||
92 | |||
93 | QCString OQCopMessage::channel() const | ||
94 | { | ||
95 | return d->m_channel; | ||
96 | } | ||
97 | |||
98 | QCString OQCopMessage::message() const | ||
99 | { | ||
100 | return d->m_message; | ||
101 | } | ||
102 | |||
103 | QByteArray OQCopMessage::data() const | ||
104 | { | ||
105 | return d->m_data; | ||
106 | } | ||
107 | |||
108 | bool OQCopMessage::isNull() const | ||
109 | { | ||
110 | return d->m_message.isNull() || d->m_channel.isNull(); | ||
111 | } | ||
112 | void OQCopMessage::setChannel ( const QCString &ch ) | ||
113 | { | ||
114 | d->m_channel = ch; | ||
115 | } | ||
116 | |||
117 | void OQCopMessage::setMessage ( const QCString &m ) | ||
118 | { | ||
119 | d->m_message = m; | ||
120 | } | ||
121 | |||
122 | void OQCopMessage::setData ( const QByteArray &data ) | ||
123 | { | ||
124 | d->m_data = data; | ||
125 | } | ||
126 | |||
127 | /*! \class Opie::ODeviceButton | ||
128 | \brief The Opie::ODeviceButton class represents a physical user mappable button on a Qtopia device. | ||
129 | |||
130 | This class represents a physical button on a Qtopia device. A | ||
131 | device may have "user programmable" buttons. | ||
132 | The location and number of buttons will vary from device to | ||
133 | device. userText() and pixmap() may be used to describe this button | ||
134 | to the user in help documentation. | ||
135 | |||
136 | \ingroup qtopiaemb | ||
137 | \internal | ||
138 | */ | ||
139 | |||
140 | ODeviceButton::ODeviceButton() | ||
141 | {} | ||
142 | |||
143 | ODeviceButton::~ODeviceButton() | ||
144 | {} | ||
145 | |||
146 | /*! | ||
147 | Returns the button's keycode. | ||
148 | */ | ||
149 | ushort ODeviceButton::keycode() const | ||
150 | { | ||
151 | return m_Keycode; | ||
152 | } | ||
153 | |||
154 | |||
155 | /*! | ||
156 | This function returns a human readable, translated description of the button. | ||
157 | */ | ||
158 | QString ODeviceButton::userText() const | ||
159 | { | ||
160 | return m_UserText; | ||
161 | } | ||
162 | |||
163 | /*! | ||
164 | This function returns the pixmap for this button. If there isn't one | ||
165 | it will return an empty (null) pixmap. | ||
166 | */ | ||
167 | QPixmap ODeviceButton::pixmap() const | ||
168 | { | ||
169 | return m_Pixmap; | ||
170 | } | ||
171 | |||
172 | /*! | ||
173 | This function returns the factory preset (default) action for when this button | ||
174 | is pressed. The return value is a legal QCop message. | ||
175 | */ | ||
176 | OQCopMessage ODeviceButton::factoryPresetPressedAction() const | ||
177 | { | ||
178 | return m_FactoryPresetPressedAction; | ||
179 | } | ||
180 | |||
181 | /*! | ||
182 | This function returns the user assigned action for when this button is pressed. | ||
183 | If no action is assigned, factoryPresetAction() is returned. | ||
184 | */ | ||
185 | OQCopMessage ODeviceButton::pressedAction() const | ||
186 | { | ||
187 | if (m_PressedAction.channel().isEmpty()) | ||
188 | return factoryPresetPressedAction(); | ||
189 | return m_PressedAction; | ||
190 | } | ||
191 | |||
192 | /*! | ||
193 | This function returns the factory preset (default) action for when this button | ||
194 | is pressed and held. The return value is a legal QCop message. | ||
195 | */ | ||
196 | OQCopMessage ODeviceButton::factoryPresetHeldAction() const | ||
197 | { | ||
198 | return m_FactoryPresetHeldAction; | ||
199 | } | ||
200 | |||
201 | /*! | ||
202 | This function returns the user assigned action for when this button is pressed | ||
203 | and held. If no action is assigned, factoryPresetAction() is returned. | ||
204 | */ | ||
205 | OQCopMessage ODeviceButton::heldAction() const | ||
206 | { | ||
207 | if (m_HeldAction.channel().isEmpty()) | ||
208 | return factoryPresetHeldAction(); | ||
209 | return m_HeldAction; | ||
210 | } | ||
211 | |||
212 | void ODeviceButton::setKeycode(ushort keycode) | ||
213 | { | ||
214 | m_Keycode = keycode; | ||
215 | } | ||
216 | |||
217 | void ODeviceButton::setUserText(const QString& text) | ||
218 | { | ||
219 | m_UserText = text; | ||
220 | } | ||
221 | |||
222 | void ODeviceButton::setPixmap(const QPixmap& picture) | ||
223 | { | ||
224 | m_Pixmap = picture; | ||
225 | } | ||
226 | |||
227 | void ODeviceButton::setFactoryPresetPressedAction(const OQCopMessage& action) | ||
228 | { | ||
229 | m_FactoryPresetPressedAction = action; | ||
230 | } | ||
231 | |||
232 | |||
233 | void ODeviceButton::setPressedAction(const OQCopMessage& action) | ||
234 | { | ||
235 | m_PressedAction = action; | ||
236 | } | ||
237 | |||
238 | void ODeviceButton::setFactoryPresetHeldAction(const OQCopMessage& action) | ||
239 | { | ||
240 | m_FactoryPresetHeldAction = action; | ||
241 | } | ||
242 | |||
243 | void ODeviceButton::setHeldAction(const OQCopMessage& action) | ||
244 | { | ||
245 | m_HeldAction = action; | ||
246 | } | ||
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 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** | ||
4 | ** This file is part of the Qtopia Environment. | ||
5 | ** | ||
6 | ** This file may be distributed and/or modified under the terms of the | ||
7 | ** GNU General Public License version 2 as published by the Free Software | ||
8 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
9 | ** packaging of this file. | ||
10 | ** | ||
11 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
12 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
13 | ** | ||
14 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
15 | ** | ||
16 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
17 | ** not clear to you. | ||
18 | ** | ||
19 | **********************************************************************/ | ||
20 | #ifndef DEVICE_BUTTON_H | ||
21 | #define DEVICE_BUTTON_H | ||
22 | |||
23 | #include <qpixmap.h> | ||
24 | #include <qstring.h> | ||
25 | |||
26 | class OQCopMessageData; | ||
27 | |||
28 | namespace Opie | ||
29 | { | ||
30 | |||
31 | class OQCopMessage | ||
32 | { | ||
33 | public: | ||
34 | OQCopMessage ( ); | ||
35 | OQCopMessage ( const OQCopMessage © ); | ||
36 | OQCopMessage ( const QCString &m_channel, const QCString &message, const QByteArray &args = QByteArray ( )); | ||
37 | |||
38 | OQCopMessage &operator = ( const OQCopMessage &assign ); | ||
39 | |||
40 | void setChannel ( const QCString &channel ); | ||
41 | void setMessage ( const QCString &message ); | ||
42 | void setData ( const QByteArray &ba ); | ||
43 | |||
44 | QCString channel ( ) const; | ||
45 | QCString message ( ) const; | ||
46 | QByteArray data ( ) const; | ||
47 | |||
48 | bool isNull()const; | ||
49 | |||
50 | bool send ( ); | ||
51 | |||
52 | private: | ||
53 | void init ( const QCString &m_channel, const QCString &message, const QByteArray &args ); | ||
54 | |||
55 | OQCopMessageData *d; | ||
56 | class Private; | ||
57 | Private* m_data; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * This class represents a physical button on a Qtopia device. A device may | ||
63 | * have n "user programmable" buttons, which are number 1..n. The location | ||
64 | * and number of buttons will vary from device to device. userText() and pixmap() | ||
65 | * may be used to describe this button to the user in help documentation. | ||
66 | * | ||
67 | * @version 1.0 | ||
68 | * @author Trolltech | ||
69 | * @short A representation of buttons | ||
70 | */ | ||
71 | |||
72 | class ODeviceButton | ||
73 | { | ||
74 | public: | ||
75 | ODeviceButton(); | ||
76 | virtual ~ODeviceButton(); | ||
77 | |||
78 | ushort keycode ( ) const; | ||
79 | QString userText ( ) const; | ||
80 | QPixmap pixmap ( ) const; | ||
81 | OQCopMessage factoryPresetPressedAction ( ) const; | ||
82 | OQCopMessage pressedAction ( ) const; | ||
83 | OQCopMessage factoryPresetHeldAction ( ) const; | ||
84 | OQCopMessage heldAction ( ) const; | ||
85 | |||
86 | void setKeycode ( ushort keycode ); | ||
87 | void setUserText ( const QString& text ); | ||
88 | void setPixmap ( const QPixmap& picture ); | ||
89 | void setFactoryPresetPressedAction ( const OQCopMessage& qcopMessage ); | ||
90 | void setPressedAction ( const OQCopMessage& qcopMessage ); | ||
91 | void setFactoryPresetHeldAction ( const OQCopMessage& qcopMessage ); | ||
92 | void setHeldAction ( const OQCopMessage& qcopMessage ); | ||
93 | |||
94 | private: | ||
95 | ushort m_Keycode; | ||
96 | QString m_UserText; | ||
97 | QPixmap m_Pixmap; | ||
98 | OQCopMessage m_FactoryPresetPressedAction; | ||
99 | OQCopMessage m_PressedAction; | ||
100 | OQCopMessage m_FactoryPresetHeldAction; | ||
101 | OQCopMessage m_HeldAction; | ||
102 | class Private; | ||
103 | Private *d; | ||
104 | }; | ||
105 | |||
106 | } | ||
107 | |||
108 | #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 | |||
@@ -1,11 +1,11 @@ | |||
1 | Package: libopiecore2 | 1 | Package: libopiecore2 |
2 | Files: $OPIEDIR/lib/libopiecore2.so.* | 2 | Files: $OPIEDIR/lib/libopiecore2.so.* |
3 | Priority: optional | 3 | Priority: optional |
4 | Section: opie/system | 4 | Section: opie/system |
5 | Maintainer: Opie Team <opie@handhelds.org> | 5 | Maintainer: Opie Team <opie@handhelds.org> |
6 | Architecture: arm | 6 | Architecture: arm |
7 | Version: 1.8.2-$SUB_VERSION.2 | 7 | Version: 1.8.3-$SUB_VERSION.2 |
8 | Depends: libqpe1 | 8 | Depends: libqpe1 |
9 | Provides: libopiecore2 | 9 | Provides: libopiecore2 |
10 | Description: Opie library 2.0 CORE | 10 | Description: Opie library 2.0 CORE |
11 | 11 | ||
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 | |||
@@ -1,26 +1,40 @@ | |||
1 | TEMPLATE = lib | 1 | TEMPLATE = lib |
2 | CONFIG += qt warn_on debug | 2 | CONFIG += qt warn_on debug |
3 | DESTDIR = $(OPIEDIR)/lib | 3 | DESTDIR = $(OPIEDIR)/lib |
4 | HEADERS = oapplication.h \ | 4 | HEADERS = oapplication.h \ |
5 | oconfig.h \ | 5 | oconfig.h \ |
6 | odebug.h \ | 6 | odebug.h \ |
7 | odevice.h \ | ||
8 | odevicebutton.h \ | ||
7 | oglobal.h \ | 9 | oglobal.h \ |
8 | oglobalsettings.h \ | 10 | oglobalsettings.h \ |
11 | oprocess.h \ | ||
12 | oprocctrl.h \ | ||
9 | ostorageinfo.h | 13 | ostorageinfo.h |
10 | 14 | ||
11 | SOURCES = oapplication.cpp \ | 15 | SOURCES = oapplication.cpp \ |
12 | oconfig.cpp \ | 16 | oconfig.cpp \ |
13 | odebug.cpp \ | 17 | odebug.cpp \ |
18 | odevice.cpp \ | ||
19 | odevicebutton.cpp \ | ||
20 | odevice_ipaq.cpp \ | ||
21 | odevice_jornada.cpp \ | ||
22 | odevice_ramses.cpp \ | ||
23 | odevice_simpad.cpp \ | ||
24 | odevice_zaurus.cpp \ | ||
25 | odevice_yopy.cpp \ | ||
14 | oglobal.cpp \ | 26 | oglobal.cpp \ |
15 | oglobalsettings.cpp \ | 27 | oglobalsettings.cpp \ |
28 | oprocess.cpp \ | ||
29 | oprocctrl.cpp \ | ||
16 | ostorageinfo.cpp | 30 | ostorageinfo.cpp |
17 | 31 | ||
18 | INTERFACES = | 32 | INTERFACES = |
19 | TARGET = opiecore2 | 33 | TARGET = opiecore2 |
20 | VERSION = 1.8.2 | 34 | VERSION = 1.8.3 |
21 | INCLUDEPATH += $(OPIEDIR)/include | 35 | INCLUDEPATH += $(OPIEDIR)/include |
22 | DEPENDPATH += $(OPIEDIR)/include | 36 | DEPENDPATH += $(OPIEDIR)/include |
23 | MOC_DIR = moc | 37 | MOC_DIR = moc |
24 | OBJECTS_DIR = obj | 38 | OBJECTS_DIR = obj |
25 | 39 | ||
26 | 40 | ||
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 @@ | |||
1 | /* This file is part of the KDE libraries | ||
2 | Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Library General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 2 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
17 | Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | // | ||
20 | // KPROCESSCONTROLLER -- A helper class for KProcess | ||
21 | // | ||
22 | // version 0.3.1, Jan, 8th 1997 | ||
23 | // | ||
24 | // (C) Christian Czezatke | ||
25 | // e9025461@student.tuwien.ac.at | ||
26 | // Ported by Holger Freyther | ||
27 | // | ||
28 | |||
29 | //#include <config.h> | ||
30 | |||
31 | #include <sys/types.h> | ||
32 | #include <sys/socket.h> | ||
33 | |||
34 | #include <errno.h> | ||
35 | #include <fcntl.h> | ||
36 | #include <stdio.h> | ||
37 | #include <string.h> | ||
38 | #include <unistd.h> | ||
39 | #include <assert.h> | ||
40 | |||
41 | #include <qsocketnotifier.h> | ||
42 | #include "oprocess.h" | ||
43 | #include "oprocctrl.h" | ||
44 | |||
45 | OProcessController *OProcessController::theOProcessController = 0; | ||
46 | |||
47 | struct sigaction OProcessController::oldChildHandlerData; | ||
48 | bool OProcessController::handlerSet = false; | ||
49 | |||
50 | OProcessController::OProcessController() | ||
51 | { | ||
52 | assert( theOProcessController == 0 ); | ||
53 | |||
54 | if (0 > pipe(fd)) | ||
55 | printf(strerror(errno)); | ||
56 | |||
57 | notifier = new QSocketNotifier(fd[0], QSocketNotifier::Read); | ||
58 | notifier->setEnabled(true); | ||
59 | QObject::connect(notifier, SIGNAL(activated(int)), | ||
60 | this, SLOT(slotDoHousekeeping(int))); | ||
61 | connect( &delayedChildrenCleanupTimer, SIGNAL( timeout()), | ||
62 | SLOT( delayedChildrenCleanup())); | ||
63 | |||
64 | theOProcessController = this; | ||
65 | |||
66 | setupHandlers(); | ||
67 | } | ||
68 | |||
69 | |||
70 | void OProcessController::setupHandlers() | ||
71 | { | ||
72 | if( handlerSet ) | ||
73 | return; | ||
74 | struct sigaction act; | ||
75 | act.sa_handler=theSigCHLDHandler; | ||
76 | sigemptyset(&(act.sa_mask)); | ||
77 | sigaddset(&(act.sa_mask), SIGCHLD); | ||
78 | // Make sure we don't block this signal. gdb tends to do that :-( | ||
79 | sigprocmask(SIG_UNBLOCK, &(act.sa_mask), 0); | ||
80 | |||
81 | act.sa_flags = SA_NOCLDSTOP; | ||
82 | |||
83 | // CC: take care of SunOS which automatically restarts interrupted system | ||
84 | // calls (and thus does not have SA_RESTART) | ||
85 | |||
86 | #ifdef SA_RESTART | ||
87 | act.sa_flags |= SA_RESTART; | ||
88 | #endif | ||
89 | |||
90 | sigaction( SIGCHLD, &act, &oldChildHandlerData ); | ||
91 | |||
92 | act.sa_handler=SIG_IGN; | ||
93 | sigemptyset(&(act.sa_mask)); | ||
94 | sigaddset(&(act.sa_mask), SIGPIPE); | ||
95 | act.sa_flags = 0; | ||
96 | sigaction( SIGPIPE, &act, 0L); | ||
97 | handlerSet = true; | ||
98 | } | ||
99 | |||
100 | void OProcessController::resetHandlers() | ||
101 | { | ||
102 | if( !handlerSet ) | ||
103 | return; | ||
104 | sigaction( SIGCHLD, &oldChildHandlerData, 0 ); | ||
105 | // there should be no problem with SIGPIPE staying SIG_IGN | ||
106 | handlerSet = false; | ||
107 | } | ||
108 | |||
109 | // block SIGCHLD handler, because it accesses processList | ||
110 | void OProcessController::addOProcess( OProcess* p ) | ||
111 | { | ||
112 | sigset_t newset, oldset; | ||
113 | sigemptyset( &newset ); | ||
114 | sigaddset( &newset, SIGCHLD ); | ||
115 | sigprocmask( SIG_BLOCK, &newset, &oldset ); | ||
116 | processList.append( p ); | ||
117 | sigprocmask( SIG_SETMASK, &oldset, 0 ); | ||
118 | } | ||
119 | |||
120 | void OProcessController::removeOProcess( OProcess* p ) | ||
121 | { | ||
122 | sigset_t newset, oldset; | ||
123 | sigemptyset( &newset ); | ||
124 | sigaddset( &newset, SIGCHLD ); | ||
125 | sigprocmask( SIG_BLOCK, &newset, &oldset ); | ||
126 | processList.remove( p ); | ||
127 | sigprocmask( SIG_SETMASK, &oldset, 0 ); | ||
128 | } | ||
129 | |||
130 | //using a struct which contains both the pid and the status makes it easier to write | ||
131 | //and read the data into the pipe | ||
132 | //especially this solves a problem which appeared on my box where slotDoHouseKeeping() received | ||
133 | //only 4 bytes (with some debug output around the write()'s it received all 8 bytes) | ||
134 | //don't know why this happened, but when writing all 8 bytes at once it works here, aleXXX | ||
135 | struct waitdata | ||
136 | { | ||
137 | pid_t pid; | ||
138 | int status; | ||
139 | }; | ||
140 | |||
141 | void OProcessController::theSigCHLDHandler(int arg) | ||
142 | { | ||
143 | struct waitdata wd; | ||
144 | // int status; | ||
145 | // pid_t this_pid; | ||
146 | int saved_errno; | ||
147 | |||
148 | saved_errno = errno; | ||
149 | // since waitpid and write change errno, we have to save it and restore it | ||
150 | // (Richard Stevens, Advanced programming in the Unix Environment) | ||
151 | |||
152 | bool found = false; | ||
153 | if( theOProcessController != 0 ) | ||
154 | { | ||
155 | // iterating the list doesn't perform any system call | ||
156 | for( QValueList<OProcess*>::ConstIterator it = theOProcessController->processList.begin(); | ||
157 | it != theOProcessController->processList.end(); | ||
158 | ++it ) | ||
159 | { | ||
160 | if( !(*it)->isRunning()) | ||
161 | continue; | ||
162 | wd.pid = waitpid( (*it)->pid(), &wd.status, WNOHANG ); | ||
163 | if ( wd.pid > 0 ) | ||
164 | { | ||
165 | ::write(theOProcessController->fd[1], &wd, sizeof(wd)); | ||
166 | found = true; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | if( !found && oldChildHandlerData.sa_handler != SIG_IGN | ||
171 | && oldChildHandlerData.sa_handler != SIG_DFL ) | ||
172 | oldChildHandlerData.sa_handler( arg ); // call the old handler | ||
173 | // handle the rest | ||
174 | if( theOProcessController != 0 ) | ||
175 | { | ||
176 | static const struct waitdata dwd = { 0, 0 } | ||
177 | ; // delayed waitpid() | ||
178 | ::write(theOProcessController->fd[1], &dwd, sizeof(dwd)); | ||
179 | } | ||
180 | else | ||
181 | { | ||
182 | int dummy; | ||
183 | while( waitpid( -1, &dummy, WNOHANG ) > 0 ) | ||
184 | ; | ||
185 | } | ||
186 | |||
187 | errno = saved_errno; | ||
188 | } | ||
189 | |||
190 | |||
191 | |||
192 | void OProcessController::slotDoHousekeeping(int ) | ||
193 | { | ||
194 | unsigned int bytes_read = 0; | ||
195 | unsigned int errcnt=0; | ||
196 | // read pid and status from the pipe. | ||
197 | struct waitdata wd; | ||
198 | while ((bytes_read < sizeof(wd)) && (errcnt < 50)) | ||
199 | { | ||
200 | int r = ::read(fd[0], ((char *)&wd) + bytes_read, sizeof(wd) - bytes_read); | ||
201 | if (r > 0) bytes_read += r; | ||
202 | else if (r < 0) errcnt++; | ||
203 | } | ||
204 | if (errcnt >= 50) | ||
205 | { | ||
206 | fprintf(stderr, | ||
207 | "Error: Max. error count for pipe read " | ||
208 | "exceeded in OProcessController::slotDoHousekeeping\n"); | ||
209 | return; // it makes no sense to continue here! | ||
210 | } | ||
211 | if (bytes_read != sizeof(wd)) | ||
212 | { | ||
213 | fprintf(stderr, | ||
214 | "Error: Could not read info from signal handler %d <> %d!\n", | ||
215 | bytes_read, sizeof(wd)); | ||
216 | return; // it makes no sense to continue here! | ||
217 | } | ||
218 | if (wd.pid==0) | ||
219 | { // special case, see delayedChildrenCleanup() | ||
220 | delayedChildrenCleanupTimer.start( 1000, true ); | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | for( QValueList<OProcess*>::ConstIterator it = processList.begin(); | ||
225 | it != processList.end(); | ||
226 | ++it ) | ||
227 | { | ||
228 | OProcess* proc = *it; | ||
229 | if (proc->pid() == wd.pid) | ||
230 | { | ||
231 | // process has exited, so do emit the respective events | ||
232 | if (proc->run_mode == OProcess::Block) | ||
233 | { | ||
234 | // If the reads are done blocking then set the status in proc | ||
235 | // but do nothing else because OProcess will perform the other | ||
236 | // actions of processHasExited. | ||
237 | proc->status = wd.status; | ||
238 | proc->runs = false; | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | proc->processHasExited(wd.status); | ||
243 | } | ||
244 | return; | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | |||
249 | // this is needed e.g. for popen(), which calls waitpid() checking | ||
250 | // for its forked child, if we did waitpid() directly in the SIGCHLD | ||
251 | // handler, popen()'s waitpid() call would fail | ||
252 | void OProcessController::delayedChildrenCleanup() | ||
253 | { | ||
254 | struct waitdata wd; | ||
255 | while(( wd.pid = waitpid( -1, &wd.status, WNOHANG ) ) > 0 ) | ||
256 | { | ||
257 | for( QValueList<OProcess*>::ConstIterator it = processList.begin(); | ||
258 | it != processList.end(); | ||
259 | ++it ) | ||
260 | { | ||
261 | if( !(*it)->isRunning() || (*it)->pid() != wd.pid ) | ||
262 | continue; | ||
263 | // it's OProcess, handle it | ||
264 | ::write(fd[1], &wd, sizeof(wd)); | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | |||
270 | OProcessController::~OProcessController() | ||
271 | { | ||
272 | assert( theOProcessController == this ); | ||
273 | resetHandlers(); | ||
274 | |||
275 | notifier->setEnabled(false); | ||
276 | |||
277 | close(fd[0]); | ||
278 | close(fd[1]); | ||
279 | |||
280 | delete notifier; | ||
281 | theOProcessController = 0; | ||
282 | } | ||
283 | |||
284 | //#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 @@ | |||
1 | /* This file is part of the KDE libraries | ||
2 | Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Library General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 2 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
17 | Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | // | ||
20 | // KPROCESSCONTROLLER -- A helper class for KProcess | ||
21 | // | ||
22 | // version 0.3.1, Jan 8th 1997 | ||
23 | // | ||
24 | // (C) Christian Czezatke | ||
25 | // e9025461@student.tuwien.ac.at | ||
26 | // Ported by Holger Freyther | ||
27 | // | ||
28 | |||
29 | #ifndef __KPROCCTRL_H__ | ||
30 | #define __KPROCCTRL_H__ | ||
31 | |||
32 | #include <qvaluelist.h> | ||
33 | #include <qtimer.h> | ||
34 | |||
35 | #include "oprocess.h" | ||
36 | |||
37 | class OProcessControllerPrivate; | ||
38 | class QSocketNotifier; | ||
39 | |||
40 | /** | ||
41 | * @short Used internally by @ref OProcess | ||
42 | * @internal | ||
43 | * @author Christian Czezakte <e9025461@student.tuwien.ac.at> | ||
44 | * | ||
45 | * A class for internal use by OProcess only. -- Exactly one instance | ||
46 | * of this class is generated by the first instance of OProcess that is | ||
47 | * created (a pointer to it gets stored in @ref theOProcessController ). | ||
48 | * | ||
49 | * This class takes care of the actual (UN*X) signal handling. | ||
50 | */ | ||
51 | class OProcessController : public QObject | ||
52 | { | ||
53 | Q_OBJECT | ||
54 | |||
55 | public: | ||
56 | OProcessController(); | ||
57 | ~OProcessController(); | ||
58 | //CC: WARNING! Destructor Not virtual (but you don't derive classes from this anyhow...) | ||
59 | |||
60 | public: | ||
61 | |||
62 | /** | ||
63 | * Only a single instance of this class is allowed at a time, | ||
64 | * and this static variable is used to track the one instance. | ||
65 | */ | ||
66 | static OProcessController *theOProcessController; | ||
67 | |||
68 | /** | ||
69 | * Automatically called upon SIGCHLD. | ||
70 | * | ||
71 | * Normally you do not need to do anything with this function but | ||
72 | * if your application needs to disable SIGCHLD for some time for | ||
73 | * reasons beyond your control, you should call this function afterwards | ||
74 | * to make sure that no SIGCHLDs where missed. | ||
75 | */ | ||
76 | static void theSigCHLDHandler(int signal); | ||
77 | // handler for sigchld | ||
78 | |||
79 | /** | ||
80 | * @internal | ||
81 | */ | ||
82 | static void setupHandlers(); | ||
83 | /** | ||
84 | * @internal | ||
85 | */ | ||
86 | static void resetHandlers(); | ||
87 | /** | ||
88 | * @internal | ||
89 | */ | ||
90 | void addOProcess( OProcess* ); | ||
91 | /** | ||
92 | * @internal | ||
93 | */ | ||
94 | void removeOProcess( OProcess* ); | ||
95 | public slots: | ||
96 | /** | ||
97 | * @internal | ||
98 | */ | ||
99 | void slotDoHousekeeping(int socket); | ||
100 | |||
101 | private slots: | ||
102 | void delayedChildrenCleanup(); | ||
103 | private: | ||
104 | int fd[2]; | ||
105 | QSocketNotifier *notifier; | ||
106 | static struct sigaction oldChildHandlerData; | ||
107 | static bool handlerSet; | ||
108 | QValueList<OProcess*> processList; | ||
109 | QTimer delayedChildrenCleanupTimer; | ||
110 | |||
111 | // Disallow assignment and copy-construction | ||
112 | OProcessController( const OProcessController& ); | ||
113 | OProcessController& operator= ( const OProcessController& ); | ||
114 | |||
115 | OProcessControllerPrivate *d; | ||
116 | }; | ||
117 | |||
118 | |||
119 | |||
120 | #endif | ||
121 | |||
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 @@ | |||
1 | /* | ||
2 | |||
3 | $Id$ | ||
4 | |||
5 | This file is part of the KDE libraries | ||
6 | Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) | ||
7 | |||
8 | This library is free software; you can redistribute it and/or | ||
9 | modify it under the terms of the GNU Library General Public | ||
10 | License as published by the Free Software Foundation; either | ||
11 | version 2 of the License, or (at your option) any later version. | ||
12 | |||
13 | This library is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | Library General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU Library General Public License | ||
19 | along with this library; see the file COPYING.LIB. If not, write to | ||
20 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | Boston, MA 02111-1307, USA. | ||
22 | |||
23 | */ | ||
24 | |||
25 | |||
26 | // | ||
27 | // KPROCESS -- A class for handling child processes in KDE without | ||
28 | // having to take care of Un*x specific implementation details | ||
29 | // | ||
30 | // version 0.3.1, Jan 8th 1998 | ||
31 | // | ||
32 | // (C) Christian Czezatke | ||
33 | // e9025461@student.tuwien.ac.at | ||
34 | // | ||
35 | // Changes: | ||
36 | // | ||
37 | // March 2nd, 1998: Changed parameter list for KShellProcess: | ||
38 | // Arguments are now placed in a single string so that | ||
39 | // <shell> -c <commandstring> is passed to the shell | ||
40 | // to make the use of "operator<<" consistent with KProcess | ||
41 | // | ||
42 | // | ||
43 | // Ported by Holger Freyther | ||
44 | // <zekce> Harlekin: oprocess and say it was ported to Qt by the Opie developers an Qt 2 | ||
45 | |||
46 | |||
47 | |||
48 | #include "oprocess.h" | ||
49 | #define _MAY_INCLUDE_KPROCESSCONTROLLER_ | ||
50 | #include "oprocctrl.h" | ||
51 | |||
52 | //#include <config.h> | ||
53 | |||
54 | #include <qfile.h> | ||
55 | #include <qsocketnotifier.h> | ||
56 | #include <qregexp.h> | ||
57 | |||
58 | #include <sys/time.h> | ||
59 | #include <sys/types.h> | ||
60 | #include <sys/stat.h> | ||
61 | #include <sys/socket.h> | ||
62 | |||
63 | #include <errno.h> | ||
64 | #include <fcntl.h> | ||
65 | #include <stdlib.h> | ||
66 | #include <signal.h> | ||
67 | #include <stdio.h> | ||
68 | #include <string.h> | ||
69 | #include <unistd.h> | ||
70 | #ifdef HAVE_SYS_SELECT_H | ||
71 | #include <sys/select.h> | ||
72 | #endif | ||
73 | #ifdef HAVE_INITGROUPS | ||
74 | #include <grp.h> | ||
75 | #endif | ||
76 | #include <pwd.h> | ||
77 | |||
78 | #include <qapplication.h> | ||
79 | #include <qmap.h> | ||
80 | //#include <kdebug.h> | ||
81 | |||
82 | ///////////////////////////// | ||
83 | // public member functions // | ||
84 | ///////////////////////////// | ||
85 | |||
86 | class OProcessPrivate | ||
87 | { | ||
88 | public: | ||
89 | OProcessPrivate() : useShell(false) { } | ||
90 | |||
91 | bool useShell; | ||
92 | QMap<QString,QString> env; | ||
93 | QString wd; | ||
94 | QCString shell; | ||
95 | }; | ||
96 | |||
97 | |||
98 | OProcess::OProcess(QObject *parent, const char *name) | ||
99 | : QObject(parent, name) | ||
100 | { | ||
101 | init ( ); | ||
102 | } | ||
103 | |||
104 | OProcess::OProcess(const QString &arg0, QObject *parent, const char *name) | ||
105 | : QObject(parent, name) | ||
106 | { | ||
107 | init ( ); | ||
108 | *this << arg0; | ||
109 | } | ||
110 | |||
111 | OProcess::OProcess(const QStringList &args, QObject *parent, const char *name) | ||
112 | : QObject(parent, name) | ||
113 | { | ||
114 | init ( ); | ||
115 | *this << args; | ||
116 | } | ||
117 | |||
118 | void OProcess::init ( ) | ||
119 | { | ||
120 | run_mode = NotifyOnExit; | ||
121 | runs = false; | ||
122 | pid_ = 0; | ||
123 | status = 0; | ||
124 | keepPrivs = false; | ||
125 | innot = 0; | ||
126 | outnot = 0; | ||
127 | errnot = 0; | ||
128 | communication = NoCommunication; | ||
129 | input_data = 0; | ||
130 | input_sent = 0; | ||
131 | input_total = 0; | ||
132 | d = 0; | ||
133 | |||
134 | if (0 == OProcessController::theOProcessController) | ||
135 | { | ||
136 | (void) new OProcessController(); | ||
137 | CHECK_PTR(OProcessController::theOProcessController); | ||
138 | } | ||
139 | |||
140 | OProcessController::theOProcessController->addOProcess(this); | ||
141 | out[0] = out[1] = -1; | ||
142 | in[0] = in[1] = -1; | ||
143 | err[0] = err[1] = -1; | ||
144 | } | ||
145 | |||
146 | void | ||
147 | OProcess::setEnvironment(const QString &name, const QString &value) | ||
148 | { | ||
149 | if (!d) | ||
150 | d = new OProcessPrivate; | ||
151 | d->env.insert(name, value); | ||
152 | } | ||
153 | |||
154 | void | ||
155 | OProcess::setWorkingDirectory(const QString &dir) | ||
156 | { | ||
157 | if (!d) | ||
158 | d = new OProcessPrivate; | ||
159 | d->wd = dir; | ||
160 | } | ||
161 | |||
162 | void | ||
163 | OProcess::setupEnvironment() | ||
164 | { | ||
165 | if (d) | ||
166 | { | ||
167 | QMap<QString,QString>::Iterator it; | ||
168 | for(it = d->env.begin(); it != d->env.end(); ++it) | ||
169 | setenv(QFile::encodeName(it.key()).data(), | ||
170 | QFile::encodeName(it.data()).data(), 1); | ||
171 | if (!d->wd.isEmpty()) | ||
172 | chdir(QFile::encodeName(d->wd).data()); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | void | ||
177 | OProcess::setRunPrivileged(bool keepPrivileges) | ||
178 | { | ||
179 | keepPrivs = keepPrivileges; | ||
180 | } | ||
181 | |||
182 | bool | ||
183 | OProcess::runPrivileged() const | ||
184 | { | ||
185 | return keepPrivs; | ||
186 | } | ||
187 | |||
188 | |||
189 | OProcess::~OProcess() | ||
190 | { | ||
191 | // destroying the OProcess instance sends a SIGKILL to the | ||
192 | // child process (if it is running) after removing it from the | ||
193 | // list of valid processes (if the process is not started as | ||
194 | // "DontCare") | ||
195 | |||
196 | OProcessController::theOProcessController->removeOProcess(this); | ||
197 | // this must happen before we kill the child | ||
198 | // TODO: block the signal while removing the current process from the process list | ||
199 | |||
200 | if (runs && (run_mode != DontCare)) | ||
201 | kill(SIGKILL); | ||
202 | |||
203 | // Clean up open fd's and socket notifiers. | ||
204 | closeStdin(); | ||
205 | closeStdout(); | ||
206 | closeStderr(); | ||
207 | |||
208 | // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess | ||
209 | delete d; | ||
210 | } | ||
211 | |||
212 | void OProcess::detach() | ||
213 | { | ||
214 | OProcessController::theOProcessController->removeOProcess(this); | ||
215 | |||
216 | runs = false; | ||
217 | pid_ = 0; | ||
218 | |||
219 | // Clean up open fd's and socket notifiers. | ||
220 | closeStdin(); | ||
221 | closeStdout(); | ||
222 | closeStderr(); | ||
223 | } | ||
224 | |||
225 | bool OProcess::setExecutable(const QString& proc) | ||
226 | { | ||
227 | if (runs) return false; | ||
228 | |||
229 | if (proc.isEmpty()) return false; | ||
230 | |||
231 | if (!arguments.isEmpty()) | ||
232 | arguments.remove(arguments.begin()); | ||
233 | arguments.prepend(QFile::encodeName(proc)); | ||
234 | |||
235 | return true; | ||
236 | } | ||
237 | |||
238 | OProcess &OProcess::operator<<(const QStringList& args) | ||
239 | { | ||
240 | QStringList::ConstIterator it = args.begin(); | ||
241 | for ( ; it != args.end() ; ++it ) | ||
242 | arguments.append(QFile::encodeName(*it)); | ||
243 | return *this; | ||
244 | } | ||
245 | |||
246 | OProcess &OProcess::operator<<(const QCString& arg) | ||
247 | { | ||
248 | return operator<< (arg.data()); | ||
249 | } | ||
250 | |||
251 | OProcess &OProcess::operator<<(const char* arg) | ||
252 | { | ||
253 | arguments.append(arg); | ||
254 | return *this; | ||
255 | } | ||
256 | |||
257 | OProcess &OProcess::operator<<(const QString& arg) | ||
258 | { | ||
259 | arguments.append(QFile::encodeName(arg)); | ||
260 | return *this; | ||
261 | } | ||
262 | |||
263 | void OProcess::clearArguments() | ||
264 | { | ||
265 | arguments.clear(); | ||
266 | } | ||
267 | |||
268 | bool OProcess::start(RunMode runmode, Communication comm) | ||
269 | { | ||
270 | uint i; | ||
271 | uint n = arguments.count(); | ||
272 | char **arglist; | ||
273 | |||
274 | if (runs || (0 == n)) | ||
275 | { | ||
276 | return false; // cannot start a process that is already running | ||
277 | // or if no executable has been assigned | ||
278 | } | ||
279 | run_mode = runmode; | ||
280 | status = 0; | ||
281 | |||
282 | QCString shellCmd; | ||
283 | if (d && d->useShell) | ||
284 | { | ||
285 | if (d->shell.isEmpty()) | ||
286 | { | ||
287 | qWarning( "Could not find a valid shell" ); | ||
288 | return false; | ||
289 | } | ||
290 | |||
291 | arglist = static_cast<char **>(malloc( (4)*sizeof(char *))); | ||
292 | for (i=0; i < n; i++) | ||
293 | { | ||
294 | shellCmd += arguments[i]; | ||
295 | shellCmd += " "; // CC: to separate the arguments | ||
296 | } | ||
297 | |||
298 | arglist[0] = d->shell.data(); | ||
299 | arglist[1] = (char *) "-c"; | ||
300 | arglist[2] = shellCmd.data(); | ||
301 | arglist[3] = 0; | ||
302 | } | ||
303 | else | ||
304 | { | ||
305 | arglist = static_cast<char **>(malloc( (n+1)*sizeof(char *))); | ||
306 | for (i=0; i < n; i++) | ||
307 | arglist[i] = arguments[i].data(); | ||
308 | arglist[n]= 0; | ||
309 | } | ||
310 | |||
311 | if (!setupCommunication(comm)) | ||
312 | qWarning( "Could not setup Communication!"); | ||
313 | |||
314 | // We do this in the parent because if we do it in the child process | ||
315 | // gdb gets confused when the application runs from gdb. | ||
316 | uid_t uid = getuid(); | ||
317 | gid_t gid = getgid(); | ||
318 | #ifdef HAVE_INITGROUPS | ||
319 | struct passwd *pw = getpwuid(uid); | ||
320 | #endif | ||
321 | |||
322 | int fd[2]; | ||
323 | if (0 > pipe(fd)) | ||
324 | { | ||
325 | fd[0] = fd[1] = 0; // Pipe failed.. continue | ||
326 | } | ||
327 | |||
328 | runs = true; | ||
329 | |||
330 | QApplication::flushX(); | ||
331 | |||
332 | // WABA: Note that we use fork() and not vfork() because | ||
333 | // vfork() has unclear semantics and is not standardized. | ||
334 | pid_ = fork(); | ||
335 | |||
336 | if (0 == pid_) | ||
337 | { | ||
338 | if (fd[0]) | ||
339 | close(fd[0]); | ||
340 | if (!runPrivileged()) | ||
341 | { | ||
342 | setgid(gid); | ||
343 | #if defined( HAVE_INITGROUPS) | ||
344 | if(pw) | ||
345 | initgroups(pw->pw_name, pw->pw_gid); | ||
346 | #endif | ||
347 | setuid(uid); | ||
348 | } | ||
349 | // The child process | ||
350 | if(!commSetupDoneC()) | ||
351 | qWarning( "Could not finish comm setup in child!" ); | ||
352 | |||
353 | setupEnvironment(); | ||
354 | |||
355 | // Matthias | ||
356 | if (run_mode == DontCare) | ||
357 | setpgid(0,0); | ||
358 | // restore default SIGPIPE handler (Harri) | ||
359 | struct sigaction act; | ||
360 | sigemptyset(&(act.sa_mask)); | ||
361 | sigaddset(&(act.sa_mask), SIGPIPE); | ||
362 | act.sa_handler = SIG_DFL; | ||
363 | act.sa_flags = 0; | ||
364 | sigaction(SIGPIPE, &act, 0L); | ||
365 | |||
366 | // We set the close on exec flag. | ||
367 | // Closing of fd[1] indicates that the execvp succeeded! | ||
368 | if (fd[1]) | ||
369 | fcntl(fd[1], F_SETFD, FD_CLOEXEC); | ||
370 | execvp(arglist[0], arglist); | ||
371 | char resultByte = 1; | ||
372 | if (fd[1]) | ||
373 | write(fd[1], &resultByte, 1); | ||
374 | _exit(-1); | ||
375 | } | ||
376 | else if (-1 == pid_) | ||
377 | { | ||
378 | // forking failed | ||
379 | |||
380 | runs = false; | ||
381 | free(arglist); | ||
382 | return false; | ||
383 | } | ||
384 | else | ||
385 | { | ||
386 | if (fd[1]) | ||
387 | close(fd[1]); | ||
388 | // the parent continues here | ||
389 | |||
390 | // Discard any data for stdin that might still be there | ||
391 | input_data = 0; | ||
392 | |||
393 | // Check whether client could be started. | ||
394 | if (fd[0]) for(;;) | ||
395 | { | ||
396 | char resultByte; | ||
397 | int n = ::read(fd[0], &resultByte, 1); | ||
398 | if (n == 1) | ||
399 | { | ||
400 | // Error | ||
401 | runs = false; | ||
402 | close(fd[0]); | ||
403 | free(arglist); | ||
404 | pid_ = 0; | ||
405 | return false; | ||
406 | } | ||
407 | if (n == -1) | ||
408 | { | ||
409 | if ((errno == ECHILD) || (errno == EINTR)) | ||
410 | continue; // Ignore | ||
411 | } | ||
412 | break; // success | ||
413 | } | ||
414 | if (fd[0]) | ||
415 | close(fd[0]); | ||
416 | |||
417 | if (!commSetupDoneP()) // finish communication socket setup for the parent | ||
418 | qWarning( "Could not finish comm setup in parent!" ); | ||
419 | |||
420 | if (run_mode == Block) | ||
421 | { | ||
422 | commClose(); | ||
423 | |||
424 | // The SIGCHLD handler of the process controller will catch | ||
425 | // the exit and set the status | ||
426 | while(runs) | ||
427 | { | ||
428 | OProcessController::theOProcessController-> | ||
429 | slotDoHousekeeping(0); | ||
430 | } | ||
431 | runs = FALSE; | ||
432 | emit processExited(this); | ||
433 | } | ||
434 | } | ||
435 | free(arglist); | ||
436 | return true; | ||
437 | } | ||
438 | |||
439 | |||
440 | |||
441 | bool OProcess::kill(int signo) | ||
442 | { | ||
443 | bool rv=false; | ||
444 | |||
445 | if (0 != pid_) | ||
446 | rv= (-1 != ::kill(pid_, signo)); | ||
447 | // probably store errno somewhere... | ||
448 | return rv; | ||
449 | } | ||
450 | |||
451 | |||
452 | |||
453 | bool OProcess::isRunning() const | ||
454 | { | ||
455 | return runs; | ||
456 | } | ||
457 | |||
458 | |||
459 | |||
460 | pid_t OProcess::pid() const | ||
461 | { | ||
462 | return pid_; | ||
463 | } | ||
464 | |||
465 | |||
466 | |||
467 | bool OProcess::normalExit() const | ||
468 | { | ||
469 | int _status = status; | ||
470 | return (pid_ != 0) && (!runs) && (WIFEXITED((_status))); | ||
471 | } | ||
472 | |||
473 | |||
474 | |||
475 | int OProcess::exitStatus() const | ||
476 | { | ||
477 | int _status = status; | ||
478 | return WEXITSTATUS((_status)); | ||
479 | } | ||
480 | |||
481 | |||
482 | |||
483 | bool OProcess::writeStdin(const char *buffer, int buflen) | ||
484 | { | ||
485 | bool rv; | ||
486 | |||
487 | // if there is still data pending, writing new data | ||
488 | // to stdout is not allowed (since it could also confuse | ||
489 | // kprocess... | ||
490 | if (0 != input_data) | ||
491 | return false; | ||
492 | |||
493 | if (runs && (communication & Stdin)) | ||
494 | { | ||
495 | input_data = buffer; | ||
496 | input_sent = 0; | ||
497 | input_total = buflen; | ||
498 | slotSendData(0); | ||
499 | innot->setEnabled(true); | ||
500 | rv = true; | ||
501 | } | ||
502 | else | ||
503 | rv = false; | ||
504 | return rv; | ||
505 | } | ||
506 | |||
507 | void OProcess::flushStdin ( ) | ||
508 | { | ||
509 | if ( !input_data || ( input_sent == input_total )) | ||
510 | return; | ||
511 | |||
512 | int d1, d2; | ||
513 | |||
514 | do | ||
515 | { | ||
516 | d1 = input_total - input_sent; | ||
517 | slotSendData ( 0 ); | ||
518 | d2 = input_total - input_sent; | ||
519 | } | ||
520 | while ( d2 <= d1 ); | ||
521 | } | ||
522 | |||
523 | void OProcess::suspend() | ||
524 | { | ||
525 | if ((communication & Stdout) && outnot) | ||
526 | outnot->setEnabled(false); | ||
527 | } | ||
528 | |||
529 | void OProcess::resume() | ||
530 | { | ||
531 | if ((communication & Stdout) && outnot) | ||
532 | outnot->setEnabled(true); | ||
533 | } | ||
534 | |||
535 | bool OProcess::closeStdin() | ||
536 | { | ||
537 | bool rv; | ||
538 | |||
539 | if (communication & Stdin) | ||
540 | { | ||
541 | communication = (Communication) (communication & ~Stdin); | ||
542 | delete innot; | ||
543 | innot = 0; | ||
544 | close(in[1]); | ||
545 | rv = true; | ||
546 | } | ||
547 | else | ||
548 | rv = false; | ||
549 | return rv; | ||
550 | } | ||
551 | |||
552 | bool OProcess::closeStdout() | ||
553 | { | ||
554 | bool rv; | ||
555 | |||
556 | if (communication & Stdout) | ||
557 | { | ||
558 | communication = (Communication) (communication & ~Stdout); | ||
559 | delete outnot; | ||
560 | outnot = 0; | ||
561 | close(out[0]); | ||
562 | rv = true; | ||
563 | } | ||
564 | else | ||
565 | rv = false; | ||
566 | return rv; | ||
567 | } | ||
568 | |||
569 | bool OProcess::closeStderr() | ||
570 | { | ||
571 | bool rv; | ||
572 | |||
573 | if (communication & Stderr) | ||
574 | { | ||
575 | communication = static_cast<Communication>(communication & ~Stderr); | ||
576 | delete errnot; | ||
577 | errnot = 0; | ||
578 | close(err[0]); | ||
579 | rv = true; | ||
580 | } | ||
581 | else | ||
582 | rv = false; | ||
583 | return rv; | ||
584 | } | ||
585 | |||
586 | |||
587 | ///////////////////////////// | ||
588 | // protected slots // | ||
589 | ///////////////////////////// | ||
590 | |||
591 | |||
592 | |||
593 | void OProcess::slotChildOutput(int fdno) | ||
594 | { | ||
595 | if (!childOutput(fdno)) | ||
596 | closeStdout(); | ||
597 | } | ||
598 | |||
599 | |||
600 | void OProcess::slotChildError(int fdno) | ||
601 | { | ||
602 | if (!childError(fdno)) | ||
603 | closeStderr(); | ||
604 | } | ||
605 | |||
606 | |||
607 | void OProcess::slotSendData(int) | ||
608 | { | ||
609 | if (input_sent == input_total) | ||
610 | { | ||
611 | innot->setEnabled(false); | ||
612 | input_data = 0; | ||
613 | emit wroteStdin(this); | ||
614 | } | ||
615 | else | ||
616 | input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent); | ||
617 | } | ||
618 | |||
619 | |||
620 | |||
621 | ////////////////////////////// | ||
622 | // private member functions // | ||
623 | ////////////////////////////// | ||
624 | |||
625 | |||
626 | |||
627 | void OProcess::processHasExited(int state) | ||
628 | { | ||
629 | if (runs) | ||
630 | { | ||
631 | runs = false; | ||
632 | status = state; | ||
633 | |||
634 | commClose(); // cleanup communication sockets | ||
635 | |||
636 | // also emit a signal if the process was run Blocking | ||
637 | if (DontCare != run_mode) | ||
638 | { | ||
639 | emit processExited(this); | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | |||
644 | |||
645 | |||
646 | int OProcess::childOutput(int fdno) | ||
647 | { | ||
648 | if (communication & NoRead) | ||
649 | { | ||
650 | int len = -1; | ||
651 | emit receivedStdout(fdno, len); | ||
652 | errno = 0; // Make sure errno doesn't read "EAGAIN" | ||
653 | return len; | ||
654 | } | ||
655 | else | ||
656 | { | ||
657 | char buffer[1024]; | ||
658 | int len; | ||
659 | |||
660 | len = ::read(fdno, buffer, 1024); | ||
661 | |||
662 | if ( 0 < len) | ||
663 | { | ||
664 | emit receivedStdout(this, buffer, len); | ||
665 | } | ||
666 | return len; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | |||
671 | |||
672 | int OProcess::childError(int fdno) | ||
673 | { | ||
674 | char buffer[1024]; | ||
675 | int len; | ||
676 | |||
677 | len = ::read(fdno, buffer, 1024); | ||
678 | |||
679 | if ( 0 < len) | ||
680 | emit receivedStderr(this, buffer, len); | ||
681 | return len; | ||
682 | } | ||
683 | |||
684 | |||
685 | |||
686 | int OProcess::setupCommunication(Communication comm) | ||
687 | { | ||
688 | int ok; | ||
689 | |||
690 | communication = comm; | ||
691 | |||
692 | ok = 1; | ||
693 | if (comm & Stdin) | ||
694 | ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, in) >= 0; | ||
695 | |||
696 | if (comm & Stdout) | ||
697 | ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, out) >= 0; | ||
698 | |||
699 | if (comm & Stderr) | ||
700 | ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, err) >= 0; | ||
701 | |||
702 | return ok; | ||
703 | } | ||
704 | |||
705 | |||
706 | |||
707 | int OProcess::commSetupDoneP() | ||
708 | { | ||
709 | int ok = 1; | ||
710 | |||
711 | if (communication != NoCommunication) | ||
712 | { | ||
713 | if (communication & Stdin) | ||
714 | close(in[0]); | ||
715 | if (communication & Stdout) | ||
716 | close(out[1]); | ||
717 | if (communication & Stderr) | ||
718 | close(err[1]); | ||
719 | |||
720 | // Don't create socket notifiers and set the sockets non-blocking if | ||
721 | // blocking is requested. | ||
722 | if (run_mode == Block) return ok; | ||
723 | |||
724 | if (communication & Stdin) | ||
725 | { | ||
726 | // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK)); | ||
727 | innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this); | ||
728 | CHECK_PTR(innot); | ||
729 | innot->setEnabled(false); // will be enabled when data has to be sent | ||
730 | QObject::connect(innot, SIGNAL(activated(int)), | ||
731 | this, SLOT(slotSendData(int))); | ||
732 | } | ||
733 | |||
734 | if (communication & Stdout) | ||
735 | { | ||
736 | // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK)); | ||
737 | outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this); | ||
738 | CHECK_PTR(outnot); | ||
739 | QObject::connect(outnot, SIGNAL(activated(int)), | ||
740 | this, SLOT(slotChildOutput(int))); | ||
741 | if (communication & NoRead) | ||
742 | suspend(); | ||
743 | } | ||
744 | |||
745 | if (communication & Stderr) | ||
746 | { | ||
747 | // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK)); | ||
748 | errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this ); | ||
749 | CHECK_PTR(errnot); | ||
750 | QObject::connect(errnot, SIGNAL(activated(int)), | ||
751 | this, SLOT(slotChildError(int))); | ||
752 | } | ||
753 | } | ||
754 | return ok; | ||
755 | } | ||
756 | |||
757 | |||
758 | |||
759 | int OProcess::commSetupDoneC() | ||
760 | { | ||
761 | int ok = 1; | ||
762 | struct linger so; | ||
763 | memset(&so, 0, sizeof(so)); | ||
764 | |||
765 | if (communication & Stdin) | ||
766 | close(in[1]); | ||
767 | if (communication & Stdout) | ||
768 | close(out[0]); | ||
769 | if (communication & Stderr) | ||
770 | close(err[0]); | ||
771 | |||
772 | if (communication & Stdin) | ||
773 | ok &= dup2(in[0], STDIN_FILENO) != -1; | ||
774 | else | ||
775 | { | ||
776 | int null_fd = open( "/dev/null", O_RDONLY ); | ||
777 | ok &= dup2( null_fd, STDIN_FILENO ) != -1; | ||
778 | close( null_fd ); | ||
779 | } | ||
780 | if (communication & Stdout) | ||
781 | { | ||
782 | ok &= dup2(out[1], STDOUT_FILENO) != -1; | ||
783 | ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so)); | ||
784 | } | ||
785 | else | ||
786 | { | ||
787 | int null_fd = open( "/dev/null", O_WRONLY ); | ||
788 | ok &= dup2( null_fd, STDOUT_FILENO ) != -1; | ||
789 | close( null_fd ); | ||
790 | } | ||
791 | if (communication & Stderr) | ||
792 | { | ||
793 | ok &= dup2(err[1], STDERR_FILENO) != -1; | ||
794 | ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&so), sizeof(so)); | ||
795 | } | ||
796 | else | ||
797 | { | ||
798 | int null_fd = open( "/dev/null", O_WRONLY ); | ||
799 | ok &= dup2( null_fd, STDERR_FILENO ) != -1; | ||
800 | close( null_fd ); | ||
801 | } | ||
802 | return ok; | ||
803 | } | ||
804 | |||
805 | |||
806 | |||
807 | void OProcess::commClose() | ||
808 | { | ||
809 | if (NoCommunication != communication) | ||
810 | { | ||
811 | bool b_in = (communication & Stdin); | ||
812 | bool b_out = (communication & Stdout); | ||
813 | bool b_err = (communication & Stderr); | ||
814 | if (b_in) | ||
815 | delete innot; | ||
816 | |||
817 | if (b_out || b_err) | ||
818 | { | ||
819 | // If both channels are being read we need to make sure that one socket buffer | ||
820 | // doesn't fill up whilst we are waiting for data on the other (causing a deadlock). | ||
821 | // Hence we need to use select. | ||
822 | |||
823 | // Once one or other of the channels has reached EOF (or given an error) go back | ||
824 | // to the usual mechanism. | ||
825 | |||
826 | int fds_ready = 1; | ||
827 | fd_set rfds; | ||
828 | |||
829 | int max_fd = 0; | ||
830 | if (b_out) | ||
831 | { | ||
832 | fcntl(out[0], F_SETFL, O_NONBLOCK); | ||
833 | if (out[0] > max_fd) | ||
834 | max_fd = out[0]; | ||
835 | delete outnot; | ||
836 | outnot = 0; | ||
837 | } | ||
838 | if (b_err) | ||
839 | { | ||
840 | fcntl(err[0], F_SETFL, O_NONBLOCK); | ||
841 | if (err[0] > max_fd) | ||
842 | max_fd = err[0]; | ||
843 | delete errnot; | ||
844 | errnot = 0; | ||
845 | } | ||
846 | |||
847 | |||
848 | while (b_out || b_err) | ||
849 | { | ||
850 | // * If the process is still running we block until we | ||
851 | // receive data. (p_timeout = 0, no timeout) | ||
852 | // * If the process has already exited, we only check | ||
853 | // the available data, we don't wait for more. | ||
854 | // (p_timeout = &timeout, timeout immediately) | ||
855 | struct timeval timeout; | ||
856 | timeout.tv_sec = 0; | ||
857 | timeout.tv_usec = 0; | ||
858 | struct timeval *p_timeout = runs ? 0 : &timeout; | ||
859 | |||
860 | FD_ZERO(&rfds); | ||
861 | if (b_out) | ||
862 | FD_SET(out[0], &rfds); | ||
863 | |||
864 | if (b_err) | ||
865 | FD_SET(err[0], &rfds); | ||
866 | |||
867 | fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout); | ||
868 | if (fds_ready <= 0) break; | ||
869 | |||
870 | if (b_out && FD_ISSET(out[0], &rfds)) | ||
871 | { | ||
872 | int ret = 1; | ||
873 | while (ret > 0) ret = childOutput(out[0]); | ||
874 | if ((ret == -1 && errno != EAGAIN) || ret == 0) | ||
875 | b_out = false; | ||
876 | } | ||
877 | |||
878 | if (b_err && FD_ISSET(err[0], &rfds)) | ||
879 | { | ||
880 | int ret = 1; | ||
881 | while (ret > 0) ret = childError(err[0]); | ||
882 | if ((ret == -1 && errno != EAGAIN) || ret == 0) | ||
883 | b_err = false; | ||
884 | } | ||
885 | } | ||
886 | } | ||
887 | |||
888 | if (b_in) | ||
889 | { | ||
890 | communication = (Communication) (communication & ~Stdin); | ||
891 | close(in[1]); | ||
892 | } | ||
893 | if (b_out) | ||
894 | { | ||
895 | communication = (Communication) (communication & ~Stdout); | ||
896 | close(out[0]); | ||
897 | } | ||
898 | if (b_err) | ||
899 | { | ||
900 | communication = (Communication) (communication & ~Stderr); | ||
901 | close(err[0]); | ||
902 | } | ||
903 | } | ||
904 | } | ||
905 | |||
906 | void OProcess::setUseShell(bool useShell, const char *shell) | ||
907 | { | ||
908 | if (!d) | ||
909 | d = new OProcessPrivate; | ||
910 | d->useShell = useShell; | ||
911 | d->shell = shell; | ||
912 | if (d->shell.isEmpty()) | ||
913 | d->shell = searchShell(); | ||
914 | } | ||
915 | |||
916 | QString OProcess::quote(const QString &arg) | ||
917 | { | ||
918 | QString res = arg; | ||
919 | res.replace(QRegExp(QString::fromLatin1("\'")), | ||
920 | QString::fromLatin1("'\"'\"'")); | ||
921 | res.prepend('\''); | ||
922 | res.append('\''); | ||
923 | return res; | ||
924 | } | ||
925 | |||
926 | QCString OProcess::searchShell() | ||
927 | { | ||
928 | QCString tmpShell = QCString(getenv("SHELL")).stripWhiteSpace(); | ||
929 | if (!isExecutable(tmpShell)) | ||
930 | { | ||
931 | tmpShell = "/bin/sh"; | ||
932 | } | ||
933 | |||
934 | return tmpShell; | ||
935 | } | ||
936 | |||
937 | bool OProcess::isExecutable(const QCString &filename) | ||
938 | { | ||
939 | struct stat fileinfo; | ||
940 | |||
941 | if (filename.isEmpty()) return false; | ||
942 | |||
943 | // CC: we've got a valid filename, now let's see whether we can execute that file | ||
944 | |||
945 | if (-1 == stat(filename.data(), &fileinfo)) return false; | ||
946 | // CC: return false if the file does not exist | ||
947 | |||
948 | // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets | ||
949 | if ( (S_ISDIR(fileinfo.st_mode)) || | ||
950 | (S_ISCHR(fileinfo.st_mode)) || | ||
951 | (S_ISBLK(fileinfo.st_mode)) || | ||
952 | #ifdef S_ISSOCK | ||
953 | // CC: SYSVR4 systems don't have that macro | ||
954 | (S_ISSOCK(fileinfo.st_mode)) || | ||
955 | #endif | ||
956 | (S_ISFIFO(fileinfo.st_mode)) || | ||
957 | (S_ISDIR(fileinfo.st_mode)) ) | ||
958 | { | ||
959 | return false; | ||
960 | } | ||
961 | |||
962 | // CC: now check for permission to execute the file | ||
963 | if (access(filename.data(), X_OK) != 0) return false; | ||
964 | |||
965 | // CC: we've passed all the tests... | ||
966 | return true; | ||
967 | } | ||
968 | |||
969 | |||
970 | |||
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 @@ | |||
1 | /* This file is part of the KDE libraries | ||
2 | Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at) | ||
3 | |||
4 | This library is free software; you can redistribute it and/or | ||
5 | modify it under the terms of the GNU Library General Public | ||
6 | License as published by the Free Software Foundation; either | ||
7 | version 2 of the License, or (at your option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
17 | Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | // | ||
20 | // KPROCESS -- A class for handling child processes in KDE without | ||
21 | // having to take care of Un*x specific implementation details | ||
22 | // | ||
23 | // version 0.3.1, Jan 8th 1998 | ||
24 | // | ||
25 | // (C) Christian Czezatke | ||
26 | // e9025461@student.tuwien.ac.at | ||
27 | // Ported by Holger Freyther to the Open Palmtop Integrated Environment | ||
28 | // | ||
29 | |||
30 | #ifndef __kprocess_h__ | ||
31 | #define __kprocess_h__ | ||
32 | |||
33 | #include <sys/types.h> // for pid_t | ||
34 | #include <sys/wait.h> | ||
35 | #include <signal.h> | ||
36 | #include <unistd.h> | ||
37 | #include <qvaluelist.h> | ||
38 | #include <qcstring.h> | ||
39 | #include <qobject.h> | ||
40 | |||
41 | class QSocketNotifier; | ||
42 | class OProcessPrivate; | ||
43 | |||
44 | /** | ||
45 | * Child process invocation, monitoring and control. | ||
46 | * | ||
47 | * @sect General usage and features | ||
48 | * | ||
49 | *This class allows a KDE and OPIE application to start child processes without having | ||
50 | *to worry about UN*X signal handling issues and zombie process reaping. | ||
51 | * | ||
52 | *@see KProcIO | ||
53 | * | ||
54 | *Basically, this class distinguishes three different ways of running | ||
55 | *child processes: | ||
56 | * | ||
57 | *@li OProcess::DontCare -- The child process is invoked and both the child | ||
58 | *process and the parent process continue concurrently. | ||
59 | * | ||
60 | *Starting a DontCare child process means that the application is | ||
61 | *not interested in any notification to determine whether the | ||
62 | *child process has already exited or not. | ||
63 | * | ||
64 | *@li OProcess::NotifyOnExit -- The child process is invoked and both the | ||
65 | *child and the parent process run concurrently. | ||
66 | * | ||
67 | *When the child process exits, the OProcess instance | ||
68 | *corresponding to it emits the Qt signal @ref processExited(). | ||
69 | * | ||
70 | *Since this signal is @em not emitted from within a UN*X | ||
71 | *signal handler, arbitrary function calls can be made. | ||
72 | * | ||
73 | *Be aware: When the OProcess objects gets destructed, the child | ||
74 | *process will be killed if it is still running! | ||
75 | *This means in particular, that you cannot use a OProcess on the stack | ||
76 | *with OProcess::NotifyOnExit. | ||
77 | * | ||
78 | *@li OProcess::Block -- The child process starts and the parent process | ||
79 | *is suspended until the child process exits. (@em Really not recommended | ||
80 | *for programs with a GUI.) | ||
81 | * | ||
82 | *OProcess also provides several functions for determining the exit status | ||
83 | *and the pid of the child process it represents. | ||
84 | * | ||
85 | *Furthermore it is possible to supply command-line arguments to the process | ||
86 | *in a clean fashion (no null -- terminated stringlists and such...) | ||
87 | * | ||
88 | *A small usage example: | ||
89 | *<pre> | ||
90 | *OProcess *proc = new OProcess; | ||
91 | * | ||
92 | **proc << "my_executable"; | ||
93 | **proc << "These" << "are" << "the" << "command" << "line" << "args"; | ||
94 | *QApplication::connect(proc, SIGNAL(processExited(OProcess *)), | ||
95 | * pointer_to_my_object, SLOT(my_objects_slot(OProcess *))); | ||
96 | *proc->start(); | ||
97 | *</pre> | ||
98 | * | ||
99 | *This will start "my_executable" with the commandline arguments "These"... | ||
100 | * | ||
101 | *When the child process exits, the respective Qt signal will be emitted. | ||
102 | * | ||
103 | *@sect Communication with the child process | ||
104 | * | ||
105 | *OProcess supports communication with the child process through | ||
106 | *stdin/stdout/stderr. | ||
107 | * | ||
108 | *The following functions are provided for getting data from the child | ||
109 | *process or sending data to the child's stdin (For more information, | ||
110 | *have a look at the documentation of each function): | ||
111 | * | ||
112 | *@li bool @ref writeStdin(char *buffer, int buflen); | ||
113 | *@li -- Transmit data to the child process's stdin. | ||
114 | * | ||
115 | *@li bool @ref closeStdin(); | ||
116 | *@li -- Closes the child process's stdin (which causes it to see an feof(stdin)). | ||
117 | *Returns false if you try to close stdin for a process that has been started | ||
118 | *without a communication channel to stdin. | ||
119 | * | ||
120 | *@li bool @ref closeStdout(); | ||
121 | *@li -- Closes the child process's stdout. | ||
122 | *Returns false if you try to close stdout for a process that has been started | ||
123 | *without a communication channel to stdout. | ||
124 | * | ||
125 | *@li bool @ref closeStderr(); | ||
126 | *@li -- Closes the child process's stderr. | ||
127 | *Returns false if you try to close stderr for a process that has been started | ||
128 | *without a communication channel to stderr. | ||
129 | * | ||
130 | * | ||
131 | *@sect QT signals: | ||
132 | * | ||
133 | *@li void @ref receivedStdout(OProcess *proc, char *buffer, int buflen); | ||
134 | *@li void @ref receivedStderr(OProcess *proc, char *buffer, int buflen); | ||
135 | *@li -- Indicates that new data has arrived from either the | ||
136 | *child process's stdout or stderr. | ||
137 | * | ||
138 | *@li void @ref wroteStdin(OProcess *proc); | ||
139 | *@li -- Indicates that all data that has been sent to the child process | ||
140 | *by a prior call to @ref writeStdin() has actually been transmitted to the | ||
141 | *client . | ||
142 | * | ||
143 | *@author Christian Czezakte e9025461@student.tuwien.ac.at | ||
144 | * | ||
145 | * | ||
146 | **/ | ||
147 | class OProcess : public QObject | ||
148 | { | ||
149 | Q_OBJECT | ||
150 | |||
151 | public: | ||
152 | |||
153 | /** | ||
154 | * Modes in which the communication channel can be opened. | ||
155 | * | ||
156 | * If communication for more than one channel is required, | ||
157 | * the values have to be or'ed together, for example to get | ||
158 | * communication with stdout as well as with stdin, you would | ||
159 | * specify @p Stdin @p | @p Stdout | ||
160 | * | ||
161 | * If @p NoRead is specified in conjunction with @p Stdout, | ||
162 | * no data is actually read from @p Stdout but only | ||
163 | * the signal @ref childOutput(int fd) is emitted. | ||
164 | */ | ||
165 | enum Communication { NoCommunication = 0, Stdin = 1, Stdout = 2, Stderr = 4, | ||
166 | AllOutput = 6, All = 7, | ||
167 | NoRead }; | ||
168 | |||
169 | /** | ||
170 | * Run-modes for a child process. | ||
171 | */ | ||
172 | enum RunMode { | ||
173 | /** | ||
174 | * The application does not receive notifications from the subprocess when | ||
175 | * it is finished or aborted. | ||
176 | */ | ||
177 | DontCare, | ||
178 | /** | ||
179 | * The application is notified when the subprocess dies. | ||
180 | */ | ||
181 | NotifyOnExit, | ||
182 | /** | ||
183 | * The application is suspended until the started process is finished. | ||
184 | */ | ||
185 | Block }; | ||
186 | |||
187 | /** | ||
188 | * Constructor | ||
189 | */ | ||
190 | OProcess(QObject *parent = 0, const char *name = 0); | ||
191 | /** | ||
192 | * Constructor | ||
193 | */ | ||
194 | OProcess(const QString &arg0, QObject *parent = 0, const char *name = 0); | ||
195 | /** | ||
196 | * Constructor | ||
197 | */ | ||
198 | OProcess(const QStringList &args, QObject *parent = 0, const char *name = 0); | ||
199 | |||
200 | /** | ||
201 | *Destructor: | ||
202 | * | ||
203 | * If the process is running when the destructor for this class | ||
204 | * is called, the child process is killed with a SIGKILL, but | ||
205 | * only if the run mode is not of type @p DontCare. | ||
206 | * Processes started as @p DontCare keep running anyway. | ||
207 | */ | ||
208 | virtual ~OProcess(); | ||
209 | |||
210 | /** | ||
211 | @deprecated | ||
212 | |||
213 | The use of this function is now deprecated. -- Please use the | ||
214 | "operator<<" instead of "setExecutable". | ||
215 | |||
216 | Sets the executable to be started with this OProcess object. | ||
217 | Returns false if the process is currently running (in that | ||
218 | case the executable remains unchanged.) | ||
219 | |||
220 | @see operator<< | ||
221 | |||
222 | */ | ||
223 | bool setExecutable(const QString& proc); | ||
224 | |||
225 | |||
226 | /** | ||
227 | * Sets the executable and the command line argument list for this process. | ||
228 | * | ||
229 | * For example, doing an "ls -l /usr/local/bin" can be achieved by: | ||
230 | * <pre> | ||
231 | * OProcess p; | ||
232 | * ... | ||
233 | * p << "ls" << "-l" << "/usr/local/bin" | ||
234 | * </pre> | ||
235 | * | ||
236 | **/ | ||
237 | OProcess &operator<<(const QString& arg); | ||
238 | /** | ||
239 | * Similar to previous method, takes a char *, supposed to be in locale 8 bit already. | ||
240 | */ | ||
241 | OProcess &operator<<(const char * arg); | ||
242 | /** | ||
243 | * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already. | ||
244 | */ | ||
245 | OProcess &operator<<(const QCString & arg); | ||
246 | |||
247 | /** | ||
248 | * Sets the executable and the command line argument list for this process, | ||
249 | * in a single method call, or add a list of arguments. | ||
250 | **/ | ||
251 | OProcess &operator<<(const QStringList& args); | ||
252 | |||
253 | /** | ||
254 | * Clear a command line argument list that has been set by using | ||
255 | * the "operator<<". | ||
256 | */ | ||
257 | void clearArguments(); | ||
258 | |||
259 | /** | ||
260 | * Starts the process. | ||
261 | * For a detailed description of the | ||
262 | * various run modes and communication semantics, have a look at the | ||
263 | * general description of the OProcess class. | ||
264 | * | ||
265 | * The following problems could cause this function to | ||
266 | * return false: | ||
267 | * | ||
268 | * @li The process is already running. | ||
269 | * @li The command line argument list is empty. | ||
270 | * @li The starting of the process failed (could not fork). | ||
271 | * @li The executable was not found. | ||
272 | * | ||
273 | * @param comm Specifies which communication links should be | ||
274 | * established to the child process (stdin/stdout/stderr). By default, | ||
275 | * no communication takes place and the respective communication | ||
276 | * signals will never get emitted. | ||
277 | * | ||
278 | * @return true on success, false on error | ||
279 | * (see above for error conditions) | ||
280 | **/ | ||
281 | virtual bool start(RunMode runmode = NotifyOnExit, | ||
282 | Communication comm = NoCommunication); | ||
283 | |||
284 | /** | ||
285 | * Stop the process (by sending it a signal). | ||
286 | * | ||
287 | * @param signoThe signal to send. The default is SIGTERM. | ||
288 | * @return @p true if the signal was delivered successfully. | ||
289 | */ | ||
290 | virtual bool kill(int signo = SIGTERM); | ||
291 | |||
292 | /** | ||
293 | @return @p true if the process is (still) considered to be running | ||
294 | */ | ||
295 | bool isRunning() const; | ||
296 | |||
297 | /** Returns the process id of the process. | ||
298 | * | ||
299 | * If it is called after | ||
300 | * the process has exited, it returns the process id of the last | ||
301 | * child process that was created by this instance of OProcess. | ||
302 | * | ||
303 | * Calling it before any child process has been started by this | ||
304 | * OProcess instance causes pid() to return 0. | ||
305 | **/ | ||
306 | pid_t pid() const; | ||
307 | |||
308 | /** | ||
309 | * Suspend processing of data from stdout of the child process. | ||
310 | */ | ||
311 | void suspend(); | ||
312 | |||
313 | /** | ||
314 | * Resume processing of data from stdout of the child process. | ||
315 | */ | ||
316 | void resume(); | ||
317 | |||
318 | /** | ||
319 | * @return @p true if the process has already finished and has exited | ||
320 | * "voluntarily", ie: it has not been killed by a signal. | ||
321 | * | ||
322 | * Note that you should check @ref OProcess::exitStatus() to determine | ||
323 | * whether the process completed its task successful or not. | ||
324 | */ | ||
325 | bool normalExit() const; | ||
326 | |||
327 | /** | ||
328 | * Returns the exit status of the process. | ||
329 | * | ||
330 | * Please use | ||
331 | * @ref OProcess::normalExit() to check whether the process has exited | ||
332 | * cleanly (i.e., @ref OProcess::normalExit() returns @p true) before calling | ||
333 | * this function because if the process did not exit normally, | ||
334 | * it does not have a valid exit status. | ||
335 | */ | ||
336 | int exitStatus() const; | ||
337 | |||
338 | |||
339 | /** | ||
340 | * Transmit data to the child process's stdin. | ||
341 | * | ||
342 | * OProcess::writeStdin may return false in the following cases: | ||
343 | * | ||
344 | * @li The process is not currently running. | ||
345 | * | ||
346 | * @li Communication to stdin has not been requested in the @ref start() call. | ||
347 | * | ||
348 | * @li Transmission of data to the child process by a previous call to | ||
349 | * @ref writeStdin() is still in progress. | ||
350 | * | ||
351 | * Please note that the data is sent to the client asynchronously, | ||
352 | * so when this function returns, the data might not have been | ||
353 | * processed by the child process. | ||
354 | * | ||
355 | * If all the data has been sent to the client, the signal | ||
356 | * @ref wroteStdin() will be emitted. | ||
357 | * | ||
358 | * Please note that you must not free "buffer" or call @ref writeStdin() | ||
359 | * again until either a @ref wroteStdin() signal indicates that the | ||
360 | * data has been sent or a @ref processHasExited() signal shows that | ||
361 | * the child process is no longer alive... | ||
362 | **/ | ||
363 | bool writeStdin(const char *buffer, int buflen); | ||
364 | |||
365 | void flushStdin(); | ||
366 | |||
367 | /** | ||
368 | * This causes the stdin file descriptor of the child process to be | ||
369 | * closed indicating an "EOF" to the child. | ||
370 | * | ||
371 | * @return @p false if no communication to the process's stdin | ||
372 | * had been specified in the call to @ref start(). | ||
373 | */ | ||
374 | bool closeStdin(); | ||
375 | |||
376 | /** | ||
377 | * This causes the stdout file descriptor of the child process to be | ||
378 | * closed. | ||
379 | * | ||
380 | * @return @p false if no communication to the process's stdout | ||
381 | * had been specified in the call to @ref start(). | ||
382 | */ | ||
383 | bool closeStdout(); | ||
384 | |||
385 | /** | ||
386 | * This causes the stderr file descriptor of the child process to be | ||
387 | * closed. | ||
388 | * | ||
389 | * @return @p false if no communication to the process's stderr | ||
390 | * had been specified in the call to @ref start(). | ||
391 | */ | ||
392 | bool closeStderr(); | ||
393 | |||
394 | /** | ||
395 | * Lets you see what your arguments are for debugging. | ||
396 | */ | ||
397 | |||
398 | const QValueList<QCString> &args() { return arguments; } | ||
399 | |||
400 | /** | ||
401 | * Controls whether the started process should drop any | ||
402 | * setuid/segid privileges or whether it should keep them | ||
403 | * | ||
404 | * The default is @p false : drop privileges | ||
405 | */ | ||
406 | void setRunPrivileged(bool keepPrivileges); | ||
407 | |||
408 | /** | ||
409 | * Returns whether the started process will drop any | ||
410 | * setuid/segid privileges or whether it will keep them | ||
411 | */ | ||
412 | bool runPrivileged() const; | ||
413 | |||
414 | /** | ||
415 | * Modifies the environment of the process to be started. | ||
416 | * This function must be called before starting the process. | ||
417 | */ | ||
418 | void setEnvironment(const QString &name, const QString &value); | ||
419 | |||
420 | /** | ||
421 | * Changes the current working directory (CWD) of the process | ||
422 | * to be started. | ||
423 | * This function must be called before starting the process. | ||
424 | */ | ||
425 | void setWorkingDirectory(const QString &dir); | ||
426 | |||
427 | /** | ||
428 | * Specify whether to start the command via a shell or directly. | ||
429 | * The default is to start the command directly. | ||
430 | * If @p useShell is true @p shell will be used as shell, or | ||
431 | * if shell is empty, the standard shell is used. | ||
432 | * @p quote A flag indicating whether to quote the arguments. | ||
433 | * | ||
434 | * When using a shell, the caller should make sure that all filenames etc. | ||
435 | * are properly quoted when passed as argument. | ||
436 | * @see quote() | ||
437 | */ | ||
438 | void setUseShell(bool useShell, const char *shell = 0); | ||
439 | |||
440 | /** | ||
441 | * This function can be used to quote an argument string such that | ||
442 | * the shell processes it properly. This is e. g. necessary for | ||
443 | * user-provided file names which may contain spaces or quotes. | ||
444 | * It also prevents expansion of wild cards and environment variables. | ||
445 | */ | ||
446 | static QString quote(const QString &arg); | ||
447 | |||
448 | /** | ||
449 | * Detaches OProcess from child process. All communication is closed. | ||
450 | * No exit notification is emitted any more for the child process. | ||
451 | * Deleting the OProcess will no longer kill the child process. | ||
452 | * Note that the current process remains the parent process of the | ||
453 | * child process. | ||
454 | */ | ||
455 | void detach(); | ||
456 | |||
457 | |||
458 | |||
459 | signals: | ||
460 | |||
461 | /** | ||
462 | * Emitted after the process has terminated when | ||
463 | * the process was run in the @p NotifyOnExit (==default option to | ||
464 | * @ref start()) or the @ref Block mode. | ||
465 | **/ | ||
466 | void processExited(OProcess *proc); | ||
467 | |||
468 | |||
469 | /** | ||
470 | * Emitted, when output from the child process has | ||
471 | * been received on stdout. | ||
472 | * | ||
473 | * To actually get | ||
474 | * these signals, the respective communication link (stdout/stderr) | ||
475 | * has to be turned on in @ref start(). | ||
476 | * | ||
477 | * @param buffer The data received. | ||
478 | * @param buflen The number of bytes that are available. | ||
479 | * | ||
480 | * You should copy the information contained in @p buffer to your private | ||
481 | * data structures before returning from this slot. | ||
482 | **/ | ||
483 | void receivedStdout(OProcess *proc, char *buffer, int buflen); | ||
484 | |||
485 | /** | ||
486 | * Emitted when output from the child process has | ||
487 | * been received on stdout. | ||
488 | * | ||
489 | * To actually get these signals, the respective communications link | ||
490 | * (stdout/stderr) has to be turned on in @ref start() and the | ||
491 | * @p NoRead flag should have been passed. | ||
492 | * | ||
493 | * You will need to explicitly call resume() after your call to start() | ||
494 | * to begin processing data from the child process's stdout. This is | ||
495 | * to ensure that this signal is not emitted when no one is connected | ||
496 | * to it, otherwise this signal will not be emitted. | ||
497 | * | ||
498 | * The data still has to be read from file descriptor @p fd. | ||
499 | **/ | ||
500 | void receivedStdout(int fd, int &len); | ||
501 | |||
502 | |||
503 | /** | ||
504 | * Emitted, when output from the child process has | ||
505 | * been received on stderr. | ||
506 | * To actually get | ||
507 | * these signals, the respective communication link (stdout/stderr) | ||
508 | * has to be turned on in @ref start(). | ||
509 | * | ||
510 | * @param buffer The data received. | ||
511 | * @param buflen The number of bytes that are available. | ||
512 | * | ||
513 | * You should copy the information contained in @p buffer to your private | ||
514 | * data structures before returning from this slot. | ||
515 | */ | ||
516 | void receivedStderr(OProcess *proc, char *buffer, int buflen); | ||
517 | |||
518 | /** | ||
519 | * Emitted after all the data that has been | ||
520 | * specified by a prior call to @ref writeStdin() has actually been | ||
521 | * written to the child process. | ||
522 | **/ | ||
523 | void wroteStdin(OProcess *proc); | ||
524 | |||
525 | |||
526 | protected slots: | ||
527 | |||
528 | /** | ||
529 | * This slot gets activated when data from the child's stdout arrives. | ||
530 | * It usually calls "childOutput" | ||
531 | */ | ||
532 | void slotChildOutput(int fdno); | ||
533 | |||
534 | /** | ||
535 | * This slot gets activated when data from the child's stderr arrives. | ||
536 | * It usually calls "childError" | ||
537 | */ | ||
538 | void slotChildError(int fdno); | ||
539 | /* | ||
540 | Slot functions for capturing stdout and stderr of the child | ||
541 | */ | ||
542 | |||
543 | /** | ||
544 | * Called when another bulk of data can be sent to the child's | ||
545 | * stdin. If there is no more data to be sent to stdin currently | ||
546 | * available, this function must disable the QSocketNotifier "innot". | ||
547 | */ | ||
548 | void slotSendData(int dummy); | ||
549 | |||
550 | protected: | ||
551 | |||
552 | /** | ||
553 | * Sets up the environment according to the data passed via | ||
554 | * setEnvironment(...) | ||
555 | */ | ||
556 | void setupEnvironment(); | ||
557 | |||
558 | /** | ||
559 | * The list of the process' command line arguments. The first entry | ||
560 | * in this list is the executable itself. | ||
561 | */ | ||
562 | QValueList<QCString> arguments; | ||
563 | /** | ||
564 | * How to run the process (Block, NotifyOnExit, DontCare). You should | ||
565 | * not modify this data member directly from derived classes. | ||
566 | */ | ||
567 | RunMode run_mode; | ||
568 | /** | ||
569 | * true if the process is currently running. You should not | ||
570 | * modify this data member directly from derived classes. For | ||
571 | * reading the value of this data member, please use "isRunning()" | ||
572 | * since "runs" will probably be made private in later versions | ||
573 | * of OProcess. | ||
574 | */ | ||
575 | bool runs; | ||
576 | |||
577 | /** | ||
578 | * The PID of the currently running process (see "getPid()"). | ||
579 | * You should not modify this data member in derived classes. | ||
580 | * Please use "getPid()" instead of directly accessing this | ||
581 | * member function since it will probably be made private in | ||
582 | * later versions of OProcess. | ||
583 | */ | ||
584 | pid_t pid_; | ||
585 | |||
586 | /** | ||
587 | * The process' exit status as returned by "waitpid". You should not | ||
588 | * modify the value of this data member from derived classes. You should | ||
589 | * rather use @ref exitStatus than accessing this data member directly | ||
590 | * since it will probably be made private in further versions of | ||
591 | * OProcess. | ||
592 | */ | ||
593 | int status; | ||
594 | |||
595 | |||
596 | /** | ||
597 | * See setRunPrivileged() | ||
598 | */ | ||
599 | bool keepPrivs; | ||
600 | |||
601 | /* | ||
602 | Functions for setting up the sockets for communication. | ||
603 | setupCommunication | ||
604 | -- is called from "start" before "fork"ing. | ||
605 | commSetupDoneP | ||
606 | -- completes communication socket setup in the parent | ||
607 | commSetupDoneC | ||
608 | -- completes communication setup in the child process | ||
609 | commClose | ||
610 | -- frees all allocated communication resources in the parent | ||
611 | after the process has exited | ||
612 | */ | ||
613 | |||
614 | /** | ||
615 | * This function is called from "OProcess::start" right before a "fork" takes | ||
616 | * place. According to | ||
617 | * the "comm" parameter this function has to initialize the "in", "out" and | ||
618 | * "err" data member of OProcess. | ||
619 | * | ||
620 | * This function should return 0 if setting the needed communication channels | ||
621 | * was successful. | ||
622 | * | ||
623 | * The default implementation is to create UNIX STREAM sockets for the communication, | ||
624 | * but you could overload this function and establish a TCP/IP communication for | ||
625 | * network communication, for example. | ||
626 | */ | ||
627 | virtual int setupCommunication(Communication comm); | ||
628 | |||
629 | /** | ||
630 | * Called right after a (successful) fork on the parent side. This function | ||
631 | * will usually do some communications cleanup, like closing the reading end | ||
632 | * of the "stdin" communication channel. | ||
633 | * | ||
634 | * Furthermore, it must also create the QSocketNotifiers "innot", "outnot" and | ||
635 | * "errnot" and connect their Qt slots to the respective OProcess member functions. | ||
636 | * | ||
637 | * For a more detailed explanation, it is best to have a look at the default | ||
638 | * implementation of "setupCommunication" in kprocess.cpp. | ||
639 | */ | ||
640 | virtual int commSetupDoneP(); | ||
641 | |||
642 | /** | ||
643 | * Called right after a (successful) fork, but before an "exec" on the child | ||
644 | * process' side. It usually just closes the unused communication ends of | ||
645 | * "in", "out" and "err" (like the writing end of the "in" communication | ||
646 | * channel. | ||
647 | */ | ||
648 | virtual int commSetupDoneC(); | ||
649 | |||
650 | |||
651 | /** | ||
652 | * Immediately called after a process has exited. This function normally | ||
653 | * calls commClose to close all open communication channels to this | ||
654 | * process and emits the "processExited" signal (if the process was | ||
655 | * not running in the "DontCare" mode). | ||
656 | */ | ||
657 | virtual void processHasExited(int state); | ||
658 | |||
659 | /** | ||
660 | * Should clean up the communication links to the child after it has | ||
661 | * exited. Should be called from "processHasExited". | ||
662 | */ | ||
663 | virtual void commClose(); | ||
664 | |||
665 | |||
666 | /** | ||
667 | * the socket descriptors for stdin/stdout/stderr. | ||
668 | */ | ||
669 | int out[2]; | ||
670 | int in[2]; | ||
671 | int err[2]; | ||
672 | |||
673 | /** | ||
674 | * The socket notifiers for the above socket descriptors. | ||
675 | */ | ||
676 | QSocketNotifier *innot; | ||
677 | QSocketNotifier *outnot; | ||
678 | QSocketNotifier *errnot; | ||
679 | |||
680 | /** | ||
681 | * Lists the communication links that are activated for the child | ||
682 | * process. Should not be modified from derived classes. | ||
683 | */ | ||
684 | Communication communication; | ||
685 | |||
686 | /** | ||
687 | * Called by "slotChildOutput" this function copies data arriving from the | ||
688 | * child process's stdout to the respective buffer and emits the signal | ||
689 | * "@ref receivedStderr". | ||
690 | */ | ||
691 | int childOutput(int fdno); | ||
692 | |||
693 | /** | ||
694 | * Called by "slotChildOutput" this function copies data arriving from the | ||
695 | * child process's stdout to the respective buffer and emits the signal | ||
696 | * "@ref receivedStderr" | ||
697 | */ | ||
698 | int childError(int fdno); | ||
699 | |||
700 | // information about the data that has to be sent to the child: | ||
701 | |||
702 | const char *input_data; // the buffer holding the data | ||
703 | int input_sent; // # of bytes already transmitted | ||
704 | int input_total; // total length of input_data | ||
705 | |||
706 | /** | ||
707 | * @ref OProcessController is a friend of OProcess because it has to have | ||
708 | * access to various data members. | ||
709 | */ | ||
710 | friend class OProcessController; | ||
711 | |||
712 | |||
713 | private: | ||
714 | /** | ||
715 | * Searches for a valid shell. | ||
716 | * Here is the algorithm used for finding an executable shell: | ||
717 | * | ||
718 | * @li Try the executable pointed to by the "SHELL" environment | ||
719 | * variable with white spaces stripped off | ||
720 | * | ||
721 | * @li If your process runs with uid != euid or gid != egid, a shell | ||
722 | * not listed in /etc/shells will not used. | ||
723 | * | ||
724 | * @li If no valid shell could be found, "/bin/sh" is used as a last resort. | ||
725 | */ | ||
726 | QCString searchShell(); | ||
727 | |||
728 | /** | ||
729 | * Used by @ref searchShell in order to find out whether the shell found | ||
730 | * is actually executable at all. | ||
731 | */ | ||
732 | bool isExecutable(const QCString &filename); | ||
733 | |||
734 | // Disallow assignment and copy-construction | ||
735 | OProcess( const OProcess& ); | ||
736 | OProcess& operator= ( const OProcess& ); | ||
737 | |||
738 | private: | ||
739 | void init ( ); | ||
740 | |||
741 | OProcessPrivate *d; | ||
742 | }; | ||
743 | |||
744 | |||
745 | |||
746 | #endif | ||
747 | |||