1 /*
2 HOTKEYS - use keys on your multimedia keyboard to control your computer
3 Copyright (C) 2000-2002 Anthony Y P Wong <ypwong@ypwong.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 $Id: hotkeys.c,v 1.32 2002/12/03 19:26:32 ypwong Exp $
20
21 Reference:
22 http://www.win.tue.nl/math/dw/personalpages/aeb/linux/kbd/scancodes.html
23 */
24
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 #include "common.h"
29
30 #include <X11/Xosdefs.h>
31 #ifndef X_NOT_STDC_ENV
32 #include <stdlib.h>
33 #else
34 extern char *getenv();
35 #endif
36
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <stdarg.h>
40 #include <db.h>
41 #include <errno.h>
42 #ifdef HAVE_GETOPT_LONG
43 #include <getopt.h>
44 #endif /* HAVE_GETOPT_LONG */
45 #include <signal.h>
46 #include <syslog.h>
47 #include <pthread.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <sys/wait.h>
51 #include <sys/time.h>
52
53 /* Mixer related */
54 #include <fcntl.h>
55 #include <sys/ioctl.h>
56 #if defined (__FreeBSD__) || defined(__DragonFly__)
57 #include <sys/soundcard.h>
58 #else
59 # if defined (__NetBSD__) || defined (__OpenBSD__)
60 # include <soundcard.h> /* OSS emulation */
61 # undef ioctl
62 # else
63 /* BSDI, Linux, Solaris */
64 # include <sys/soundcard.h>
65 # endif /* __NetBSD__ or __OpenBSD__ */
66 #endif /* __FreeBSD__ */
67
68 /* CDROM related */
69 //#include <linux/cdrom.h> /* FIXME: linux specific! */
70 /* APM (suspend/standby) support */
71 //#include "apm.h"
72 #if HAVE_GTK
73 #include "splash.h"
74 #endif
75
76 #include "hotkeys.h"
77 #include "conf.h"
78
79 #include <X11/Xmu/Error.h>
80
81 #define lowbit(x) ((x) & (-(x)))
82 #define M(m) fprintf(stderr,(m))
83 #define M1(m,a) fprintf(stderr,(m),(a))
84
85 /***====================================================================***/
86
87 char * dpyName = NULL;
88 Display * dpy = NULL;
89 char * cfgFileName = NULL;
90 int xkbOpcode = 0;
91 int xkbEventCode = 0;
92 XkbDescPtr xkb = NULL;
93 Bool dummyErrFlag = False;
94
95 Bool synch = False;
96 int verbose = 0;
97 int loglevel = 0;
98 Bool background = True;
99 Bool noSplash = False;
100
101 FILE * errorFile = NULL;
102
103 char * progname = NULL;
104
105 char * cdromDevice = CDROM_DEV;
106
107 keyboard kbd; /* the keyboard the user is using */
108
109 #ifdef HAVE_LIBXOSD
110 xosd * osd = (xosd*)1;
111 #endif
112
113 int volUpAdj = 2;
114 int volDownAdj = -2;
115
116 /***====================================================================***/
117
118 void
usage(int argc,char * argv[])119 usage(int argc, char *argv[])
120 {
121 char cmplStr[256] = {'\0'};
122 int first = 1;
123
124 #ifdef HAVE_LIBXOSD
125 strcat(cmplStr,"XOSD");
126 first = 0;
127 #endif
128 #if HAVE_GTK
129 if ( first == 0 )
130 {
131 strcat(cmplStr,",GTK");
132 }
133 else
134 {
135 strcat(cmplStr,"GTK");
136 first = 0;
137 }
138 #endif
139
140 printf("HOTKEYS v" VERSION " -- use the hotkeys on your Internet/multimedia keyboard to control your computer");
141 if (strlen(cmplStr))
142 printf(" (compile option(s): %s)", cmplStr);
143 printf("\n");
144 printf("Usage: %s [options...]\n", argv[0]);
145 printf("Legal options:\n");
146 #ifdef HAVE_GETOPT_LONG
147 printf(" -t, --type=TYPE Specify the keyboard type (refer to -l)\n");
148 printf(" -l, --kbd-list Show all supported keyboards\n");
149 printf(" -d, --cdrom-dev=DEVICE Specify the CDROM/DVDROM device, or 'none'\n");
150 #ifdef HAVE_LIBXOSD
151 printf(" -o, --osd=STATE Turn off/on on-screen display\n");
152 #endif
153 printf(" -L, --loglevel=LEVEL Set the log level in syslog [0-7]\n");
154 printf(" -b, --no-background Do not run in the background\n");
155 printf(" -F, --fix-vmware=TIME Use this if you use vmware at the same time\n");
156 #if HAVE_GTK
157 printf(" -Z, --no-splash No splash screen\n");
158 #endif
159 printf(" -h, --help Print this message\n");
160 /*
161 M("-cfg <file> Specify a config file\n");
162 M("-d[isplay] <dpy> Specify the display to watch\n");
163 M("-v Print verbose messages\n");
164 */
165 #else /* HAVE_GETOPT_LONG */
166 printf(" -t TYPE Specify the keyboard type (refer to -l)\n");
167 printf(" -l Show all supported keyboards\n");
168 printf(" -d DEVICE Specify the CDROM/DVDROM device, 'none' for no device\n");
169 #ifdef HAVE_LIBXOSD
170 printf(" -o STATE Turn off/on on-screen display\n");
171 #endif
172 printf(" -L LEVEL Set the log level in syslog [0-7]\n");
173 printf(" -b Do not run in the background\n");
174 printf(" -F TIME Use this option if vmware is used concurrently\n");
175 #if HAVE_GTK
176 printf(" -Z No splash screen\n");
177 #endif
178 printf(" -h Print this message\n");
179 #endif /* HAVE_GETOPT_LONG */
180 }
181
182
183 void
showKbdList(int argc,char * argv[])184 showKbdList(int argc, char *argv[])
185 {
186 DIR* dir;
187 struct dirent* ent;
188 char* homedir;
189 char* h;
190 int flag = 0;
191 int len;
192
193 #ifdef HAVE_GETOPT_LONG
194 printf("Supported keyboards: (with corresponding options to --kbd-list or -l)\n");
195 #else
196 printf("Supported keyboards: (with corresponding options to -l)\n");
197 #endif
198
199 /* Read the definition files in $HOME/.hotkeys */
200 if ( (h = getenv("HOME")) != NULL )
201 {
202 homedir = XMALLOC( char, strlen(h) + strlen("/.hotkeys") + 1 );
203 strcpy( homedir, h );
204 strcat( homedir, "/.hotkeys" );
205 if ( ( dir = opendir(homedir) ) != NULL )
206 {
207 while ( ent = readdir(dir) )
208 {
209 len = NLENGTH(ent);
210 /* Show all files that ends with ".def" */
211 if ( len > 4 &&
212 strncmp( &(ent->d_name[len-4]), ".def", 4 ) == 0 )
213 {
214 ent->d_name[ len-4 ] = '\0';
215 if ( setKbdType(NULL, ent->d_name) == True )
216 {
217 printf( " %s\t- %s\n", ent->d_name, kbd.longName );
218 flag = 1;
219 }
220 }
221 }
222 }
223 XFREE(homedir);
224 }
225 else
226 {
227 homedir = NULL;
228 }
229
230 /* Read the default location: SHAREDIR */
231 if ( ( dir = opendir(SHAREDIR) ) != NULL )
232 {
233 while ( ent = readdir(dir) )
234 {
235 len = NLENGTH(ent);
236 /* Show all files that ends with ".def" in SHAREDIR */
237 if ( len > 4 &&
238 strncmp( &(ent->d_name[len-4]), ".def", 4 ) == 0 )
239 {
240 ent->d_name[ len-4 ] = '\0';
241 if ( setKbdType(NULL, ent->d_name) == True )
242 {
243 printf( " %s\t- %s\n", ent->d_name, kbd.longName );
244 flag = 1;
245 }
246 }
247 }
248 }
249
250 if ( flag == 0 )
251 {
252 printf( "NONE FOUND. Probably due to an unsuccessful installation.\n");
253 }
254
255 closedir(dir);
256 }
257
258
259 static Bool
setKbdType(const char * prog,const char * type)260 setKbdType(const char* prog, const char* type)
261 {
262 char* defname;
263 char* h;
264 Bool ret = True;
265
266 /* Make up the complete filename, try the user's HOME first */
267 if ( (h = getenv("HOME")) != NULL )
268 {
269 /* Make up the complete filename */
270 defname = XMALLOC( char, strlen(h) +
271 strlen("/.hotkeys/") +
272 strlen(type) + 5 );
273 strcpy( defname, h );
274 strcat( defname, "/.hotkeys/" );
275 strcat( defname, type );
276 strcat( defname, ".def" );
277 if ( testReadable(defname) ) /* if the file exists... */
278 {
279 ret = readDefFile( defname );
280 }
281 else
282 {
283 /* Now try if it exists in SHAREDIR or not */
284 XFREE( defname );
285 defname = XMALLOC( char, strlen(SHAREDIR)+strlen(type)+6 );
286 strcpy( defname, SHAREDIR );
287 strcat( defname, "/" );
288 strcat( defname, type );
289 strcat( defname, ".def" );
290
291 if ( testReadable(defname) ) /* if the file exists... */
292 {
293 ret = readDefFile( defname );
294 }
295 else
296 {
297 /* No matching keyboard type */
298 if ( prog != NULL )
299 {
300 uInfo("Keyboard type `%s' is not supported.\n"
301 "Use %s --kbd-list to list all supported keyboard\n",
302 type, prog);
303 exit(0);
304 }
305 else
306 {
307 ret = False;
308 }
309 }
310 }
311 }
312
313 XFREE( defname );
314 return ret;
315 }
316
317 /* Option is --cdrom-dev or -d */
318 void
setCDROMDevice(char * optarg)319 setCDROMDevice(char* optarg)
320 {
321 int fd;
322
323 if ( strncasecmp( optarg, "none", 4 ) == 0 )
324 {
325 cdromDevice = NULL;
326 return;
327 }
328 if ( (fd = open( optarg, O_RDONLY|O_NONBLOCK )) == -1)
329 {
330 uInfo("Unable to open `%s', fall back to %s\n", optarg, CDROM_DEV);
331 }
332 else
333 {
334 if ( ( cdromDevice = (char*) xstrdup(optarg) ) == NULL )
335 {
336 uError("Insufficient memory");
337 bailout();
338 }
339 }
340 close (fd);
341 }
342
343
344 static void
setLoglevel(int level)345 setLoglevel(int level)
346 {
347 /* Map the supplied level to the one defined in syslog.h */
348 switch (level)
349 {
350 case 0: loglevel = LOG_EMERG; break;
351 case 1: loglevel = LOG_ALERT; break;
352 case 2: loglevel = LOG_CRIT; break;
353 case 3: loglevel = LOG_ERR; break;
354 case 4: loglevel = LOG_WARNING; break;
355 case 5: loglevel = LOG_NOTICE; break;
356 case 6: loglevel = LOG_INFO; break;
357 case 7: loglevel = LOG_DEBUG; break;
358 default: loglevel = LOG_ERR; break;
359 }
360 setlogmask( LOG_UPTO(loglevel) );
361 }
362
363 #ifdef HAVE_LIBXOSD
364 static void
toggleOSD(char * optarg)365 toggleOSD(char* optarg)
366 {
367 int arg = 0;
368
369 if ( strncasecmp( optarg, "on", 2 ) == 0 ||
370 strncasecmp( optarg, "1", 1 ) == 0 ||
371 strncasecmp( optarg, "yes", 3 ) == 0 )
372 {
373 arg = 1;
374 }
375 else
376 if ( strncasecmp( optarg, "off", 3 ) != 0 &&
377 strncasecmp( optarg, "0", 1 ) != 0 &&
378 strncasecmp( optarg, "no", 2 ) != 0 )
379 {
380 uInfo("Unknown argument: %s, assuming on\n", optarg);
381 arg = 1;
382 }
383
384 if ( !arg )
385 {
386 osd = NULL;
387 }
388 }
389 #endif /* HAVE_LIBXOSD */
390
391 /***====================================================================***/
392
393 static Bool
parseArgs(int argc,char * argv[])394 parseArgs(int argc, char *argv[])
395 {
396 int c, i;
397 int digit_optind = 0;
398
399 const char *flags = "hbt:d:lz:vL:F:"
400 #ifdef HAVE_LIBXOSD
401 "o:"
402 #endif
403 #if HAVE_GTK
404 "Z"
405 #endif
406 ;
407 #ifdef HAVE_GETOPT_LONG
408 int this_option_optind = optind ? optind : 1;
409 int option_index = 0;
410 static struct option long_options[] =
411 {
412 {"help", 0, 0, 'h'},
413 {"background", 0, 0, 'b'},
414 {"type", 1, 0, 't'},
415 {"cdrom-dev", 1, 0, 'd'},
416 {"kbd-list", 0, 0, 'l'},
417 {"verbose", 0, 0, 'v'},
418 {"loglevel", 1, 0, 'L'},
419 #ifdef HAVE_LIBXOSD
420 {"osd", 1, 0, 'o'},
421 #endif
422 {"fix-vmware", 2, 0, 'F'},
423 #if HAVE_GTK
424 {"no-splash", 0, 0, 'Z'},
425 #endif
426 {0, 0, 0, 0}
427 };
428 #endif /* HAVE_GETOPT_LONG */
429
430 if ( strrchr( argv[0], '/' ) ) {
431 /* strip the directories */
432 progname = (char*) strrchr( argv[0], '/' ) + 1;
433 } else {
434 progname = argv[0];
435 }
436
437 #ifdef HAVE_GETOPT_LONG
438 while ((c = getopt_long(argc, argv, flags, long_options, &option_index)) != -1) {
439 #else
440 while ((c = getopt(argc, argv, flags)) != -1) {
441 #endif /* HAVE_GETOPT_LONG */
442
443 switch (c)
444 {
445 #if 0
446 #ifdef HAVE_GETOPT_LONG
447 case 0:
448
449 if ( strncmp( long_options[option_index].name, "type", 4 ) == 0 )
450 {
451 setKbdType(argv[0], optarg);
452 } else
453 if ( strncmp( long_options[option_index].name, "cdrom-dev", 9 ) == 0 )
454 {
455 setCDROMDevice(optarg);
456 }
457 break;
458 #endif /* HAVE_GETOPT_LONG */
459 #endif
460
461 case 't':
462 setConfig( "Kbd", optarg, 0 );
463 break;
464 case 'd':
465 setConfig( "CDROM", optarg, 0 );
466 break;
467 case 'h':
468 usage(argc, argv);
469 exit(0);
470 break;
471 case 'b':
472 background = False;
473 break;
474 case 'l':
475 showKbdList(argc, argv);
476 exit(0);
477 break;
478 case 'L':
479 setLoglevel(atoi(optarg));
480 break;
481 #ifdef HAVE_LIBXOSD
482 case 'o':
483 toggleOSD(optarg);
484 break;
485 #endif
486 case 'F':
487 fixVMware(optarg);
488 break;
489 #if HAVE_GTK
490 case 'Z':
491 noSplash=True;
492 break;
493 #endif
494 case 'z':
495 break;
496 case '?':
497 break;
498
499 }
500 }
501
502 if ( getConfig("Kbd")[0] )
503 {
504 setKbdType( argv[0], getConfig("Kbd") );
505 }
506 else
507 {
508 uInfo("You must set the keyboard type, use %s -t <type> to set it.\n", argv[0]);
509 exit(1);
510 }
511
512 if ( getConfig("CDROM")[0] )
513 setCDROMDevice( getConfig("CDROM") );
514
515 /* check for a single additional argument */
516 if ((argc - optind) > 1) {
517 fprintf( stderr, "%s: too many arguments\n", argv[0] );
518 bailout();
519 }
520
521 return True;
522 }
523
524 /* Copied from xkbevd */
525 static Display *
526 GetDisplay(char* program, char* dpyName, int* opcodeRtrn, int* evBaseRtrn)
527 {
528 int mjr,mnr,error;
529 Display *dpy;
530
531 mjr = XkbMajorVersion;
532 mnr = XkbMinorVersion;
533 dpy = XkbOpenDisplay(dpyName,evBaseRtrn,NULL,&mjr,&mnr,&error);
534 if (dpy == NULL)
535 {
536 switch (error)
537 {
538 case XkbOD_BadLibraryVersion:
539 uInfo("%s was compiled with XKB version %d.%02d\n",
540 program,XkbMajorVersion,XkbMinorVersion);
541 uInfo("X library supports incompatible version %d.%02d\n",
542 mjr,mnr);
543 break;
544 case XkbOD_ConnectionRefused:
545 uInfo("Cannot open display \"%s\"\n",dpyName);
546 break;
547 case XkbOD_NonXkbServer:
548 uInfo("XKB extension not present on %s\n",dpyName);
549 break;
550 case XkbOD_BadServerVersion:
551 uInfo("%s was compiled with XKB version %d.%02d\n",
552 program,XkbMajorVersion,XkbMinorVersion);
553 uInfo("Server %s uses incompatible version %d.%02d\n",
554 dpyName,mjr,mnr);
555 break;
556 default:
557 uInternalError("Unknown error %d from XkbOpenDisplay\n",error);
558 }
559 }
560 else
561 {
562 if (synch)
563 XSynchronize(dpy,True);
564 if (opcodeRtrn)
565 XkbQueryExtension(dpy,opcodeRtrn,evBaseRtrn,NULL,&mjr,&mnr);
566 }
567 return dpy;
568 }
569
570 void
571 bailout(void)
572 {
573 if ( dpy != NULL )
574 XCloseDisplay(dpy);
575 uInfo("Bailing out...\n");
576 exit(1);
577 }
578
579
580 /*
581 * adj is a percentage, can be +ve or -ve for louder and softer resp.
582 */
583 static int
584 adjustVol(int adj)
585 {
586 int mixer_fd = -1, cdrom_fd = -1;
587 int master_vol, cd_vol;
588 // struct cdrom_volctrl cdrom_vol;
589 int left, right;
590 static struct timeval last_time;
591 struct timeval this_time;
592 static int multiplier = 0; /* if 0 then it's first time to come in this func */
593 int ret = 0;
594
595 int sign = adj > 0 ? 1 : -1;
596
597 if ( adj == 0 )
598 return 0;
599
600 if ( multiplier == 0 )
601 {
602 gettimeofday(&last_time, NULL);
603 multiplier = sign;
604 }
605 else
606 {
607 gettimeofday(&this_time, NULL);
608 if ( (( adj > 0 && multiplier > 0 ) || ( adj < 0 && multiplier < 0 )) &&
609 ( (this_time.tv_sec - last_time.tv_sec) * 1000000 +
610 this_time.tv_usec - last_time.tv_usec < 500000 ) )
611 {
612 multiplier += sign;
613 adj *= abs(multiplier);
614 if ( adj > 10 ) /* should be a MAX value defined somewhere else FIXME */
615 adj = 10;
616 else if ( adj < -10 )
617 adj = -10;
618 }
619 else
620 {
621 multiplier = sign;
622 }
623 last_time.tv_sec = this_time.tv_sec;
624 last_time.tv_usec = this_time.tv_usec;
625 }
626
627 /* open the mixer device */
628 if ( (mixer_fd = open( MIXER_DEV, O_RDWR|O_NONBLOCK )) == -1 )
629 {
630 uError("Unable to open `%s'", MIXER_DEV);
631 }
632 else
633 {
634 if ( SOUND_IOCTL(mixer_fd, SOUND_MIXER_READ_VOLUME, &master_vol) == -1)
635 {
636 uError("Unable to read the volume of `%s'", MIXER_DEV);
637 ret = -1;
638 }
639 else
640 {
641 /* Set the master volume */
642 left = (master_vol & 0xFF) + adj;
643 right = ((master_vol >> 8) & 0xFF) + adj;
644 left = (left>MAXLEVEL) ? MAXLEVEL : ((left<0) ? 0 : left);
645 right = (right>MAXLEVEL) ? MAXLEVEL : ((right<0) ? 0 : right);
646 master_vol = left + (right << 8);
647
648 if (SOUND_IOCTL(mixer_fd, SOUND_MIXER_WRITE_VOLUME, &master_vol) == -1)
649 {
650 uError("Unable to set the master volume");
651 ret = -1;
652 }
653 #ifdef HAVE_LIBXOSD
654 else if (osd)
655 {
656 xosd_display(osd, 0, XOSD_string, "Volume");
657 xosd_display(osd, 1, XOSD_percentage, (((left+right)/2)*100/MAXLEVEL));
658 }
659 #endif
660 }
661 #if 0
662 if ( SOUND_IOCTL(mixer_fd, SOUND_MIXER_READ_CD, &cd_vol) == -1)
663 {
664 uError("Unable to read the CD volume of `%s'", MIXER_DEV);
665 ret = -1; goto LEAVE;
666 }
667 else
668 {
669 /* Set the CD volume */
670 left = (cd_vol & 0xFF) + adj;
671 right = ((cd_vol >> 8) & 0xFF) + adj;
672 left = (left>MAXLEVEL) ? MAXLEVEL : ((left<0) ? 0 : left);
673 right = (right>MAXLEVEL) ? MAXLEVEL : ((right<0) ? 0 : right);
674 cd_vol = left + (right << 8);
675
676 if (SOUND_IOCTL(mixer_fd, SOUND_MIXER_WRITE_CD, &cd_vol) == -1)
677 {
678 uError("Unable to set the CD volume");
679 ret = -1; goto LEAVE;
680 }
681 }
682 #endif
683 }
684
685 /* open the cdrom/dvdrom drive device */
686 /***** ANDY: No CD support yet
687 if ( cdromDevice != NULL )
688 {
689 if ( (cdrom_fd = open( cdromDevice, O_RDONLY|O_NONBLOCK )) == -1 )
690 {
691 uError("Unable to open `%s'", cdromDevice);
692 }
693 else
694 {
695 || read the cdrom volume ||
696 if ( ioctl(cdrom_fd, CDROMVOLREAD, &cdrom_vol) == -1 )
697 {
698 uError("Unable to read the CDROM volume of `%s'", cdromDevice);
699 ret = -1;
700 }
701 else
702 {
703 || Set the CDROM volume ||
704 int t;
705 float myAdj;
706 myAdj = 0xFF / 100.0 * adj;
707 t = cdrom_vol.channel0 + myAdj;
708 cdrom_vol.channel0 = (t < 0 ? 0 : (t > 0xFF ? 0xFF : t));
709 t = cdrom_vol.channel1 + myAdj;
710 cdrom_vol.channel1 = (t < 0 ? 0 : (t > 0xFF ? 0xFF : t));
711 #if 0
712 t = cdrom_vol.channel2 + myAdj;
713 cdrom_vol.channel2 = (t < 0 ? 0 : (t > 0xFF ? 0xFF : t));
714 t = cdrom_vol.channel3 + myAdj;
715 cdrom_vol.channel3 = (t < 0 ? 0 : (t > 0xFF ? 0xFF : t));
716 #endif
717 if ( ioctl(cdrom_fd, CDROMVOLCTRL, &cdrom_vol) == -1 )
718 {
719 uError("Unable to set the volume of %s", cdromDevice);
720 ret = -1;
721 }
722 }
723 }
724 }
725 END Andy *****/
726
727 if (mixer_fd != -1) close(mixer_fd);
728 //Andy if (cdrom_fd != -1) close(cdrom_fd);
729
730 return ret;
731 }
732
733
734 /*
735 * Mute or un-mute the /dev/mixer master volume and CDROM drive's volume
736 */
737 static int
738 doMute(void)
739 {
740 static Bool muted = False;
741 static int last_mixer_vol, last_cd_vol;
742 //Andy static struct cdrom_volctrl last_cdrom_vol;
743
744 int vol, cd_vol;
745 //Andy struct cdrom_volctrl cdrom_vol;
746 int mixer_fd = -1, cdrom_fd = -1;
747
748 short ret = 0; /* return value */
749
750 /* open the mixer device */
751 if ( (mixer_fd = open( MIXER_DEV, O_RDWR|O_NONBLOCK )) == -1 )
752 {
753 uError("Unable to open `%s'", MIXER_DEV);
754 }
755 /* open the cdrom/dvdrom drive device */
756 /***** Andy: No CD support
757 if ( cdromDevice != NULL )
758 {
759 if ( (cdrom_fd = open( cdromDevice, O_RDONLY|O_NONBLOCK )) == -1 )
760 {
761 uError("Unable to open `%s'", cdromDevice);
762 }
763 }
764 END Andy *****/
765
766 if ( muted )
767 {
768 /* Un-mute them */
769 if (mixer_fd != -1)
770 {
771 if (SOUND_IOCTL(mixer_fd, SOUND_MIXER_WRITE_VOLUME, &last_mixer_vol) == -1)
772 {
773 uError("Unable to un-mute the mixer");
774 ret = -1;
775 }
776 else
777 {
778 muted = False;
779 #ifdef HAVE_LIBXOSD
780 if (osd)
781 {
782 int left = last_mixer_vol & 0xFF,
783 right = (last_mixer_vol >> 8) & 0xFF;
784 xosd_display(osd, 0, XOSD_string, "Unmute");
785 // xosd_display(osd, 1, XOSD_percentage, (((left+right)/2)*100/MAXLEVEL));
786 }
787 #endif
788 }
789 }
790 /***** Andy: No CD support
791 #if 0
792 if (SOUND_IOCTL(mixer_fd, SOUND_MIXER_WRITE_CD, &last_cd_vol) == -1)
793 {
794 uError("Unable to un-mute the CD volume");
795 ret = -1;
796 } else
797 muted = False;
798 #endif
799 if (cdrom_fd != -1)
800 {
801 if ( ioctl(cdrom_fd, CDROMVOLCTRL, &last_cdrom_vol) == -1 )
802 {
803 uError("Unable to un-mute `%s'", cdromDevice);
804 ret = -1;
805 } else
806 muted = False;
807 }
808 End Andy *****/
809 }
810 else /* ! muted */
811 {
812
813 /* Read and store the mixer volume, do not try to mute them
814 * if we cannot read any of their values. */
815
816 if (mixer_fd != -1)
817 {
818 if ( SOUND_IOCTL(mixer_fd, SOUND_MIXER_READ_VOLUME, &last_mixer_vol) == -1)
819 {
820 uError("Unable to read the mixer volume of `%s'", MIXER_DEV);
821 ret = -1;
822 }
823 else
824 {
825 /* Mute it! */
826 vol = 0;
827 if (SOUND_IOCTL(mixer_fd, SOUND_MIXER_WRITE_VOLUME, &vol) == -1)
828 {
829 uError("Unable to mute mixer volume of `%s'", MIXER_DEV);
830 ret = -1;
831 }
832 else
833 {
834 muted = True;
835 #ifdef HAVE_LIBXOSD
836 if (osd)
837 {
838 xosd_set_timeout(osd, -1);
839 xosd_display(osd, 0, XOSD_string, "Mute");
840 xosd_display(osd, 1, XOSD_string, "");
841 }
842 #endif
843 }
844 }
845 }
846 /***** Andy: No CD support
847 #if 0
848 if ( SOUND_IOCTL(mixer_fd, SOUND_MIXER_READ_CD, &last_cd_vol) == -1)
849 {
850 uError("Unable to read the CD volume of `%s'", MIXER_DEV);
851 ret = -1; goto LEAVE2;
852 }
853 else
854 {
855 if (SOUND_IOCTL(mixer_fd, SOUND_MIXER_WRITE_CD, &vol) == -1)
856 {
857 uError("Unable to mute CD volume of `%s'", MIXER_DEV);
858 ret = -1;
859 } else
860 muted = True;
861 }
862 #endif
863 End Andy *****/
864 /* read and store the cdrom volume */
865 /***** Andy: No CD support
866 if (cdrom_fd != -1)
867 {
868 if ( ioctl(cdrom_fd, CDROMVOLREAD, &last_cdrom_vol) == -1 )
869 {
870 uError("Unable to read the CDROM volume of `%s'", cdromDevice);
871 ret = -1;
872 }
873 else
874 {
875 || Set the volume to 0. FIXME: is this linux specific? Do
876 * other platforms also have 4 channels? ||
877 cdrom_vol.channel0 = cdrom_vol.channel1 = cdrom_vol.channel2 =
878 cdrom_vol.channel3 = 0;
879 if ( ioctl(cdrom_fd, CDROMVOLCTRL, &cdrom_vol) == -1 )
880 {
881 uError("Unable to mute `%s'", cdromDevice);
882 ret = -1;
883 } else
884 muted = True;
885 }
886 }
887 End Andy *****/
888 }
889
890 if (mixer_fd != -1) close(mixer_fd);
891 //Andy if (cdrom_fd != -1) close(cdrom_fd);
892
893 return ret;
894 }
895
896 static int
897 ejectDisc(void)
898 {
899 /***** Andy: No CD support
900 int fd, status;
901
902 if ( cdromDevice == NULL )
903 return 0;
904
905 || the idea of this code is from xine's vcd plugin, mostly linux
906 specific FIXME ||
907 if ( (fd = open( cdromDevice, O_RDONLY | O_NONBLOCK)) > -1 ) {
908 status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
909 switch (status)
910 {
911 || Looks like ATAPI drives doesn't return CDS_TRAY_OPEN,
912 * at least it's the case on my ASUS DVD drive... ||
913 case CDS_TRAY_OPEN:
914 #ifdef HAVE_LIBXOSD
915 if ( osd )
916 {
917 xosd_display(osd, 0, XOSD_string, "Close tray");
918 xosd_display(osd, 1, XOSD_string, "");
919 }
920 #endif
921 if ( (ioctl(fd, CDROMCLOSETRAY)) != 0 ) {
922 SYSLOG( LOG_NOTICE, "CDROMCLOSETRAY failed: %s\n",
923 strerror(errno) );
924 }
925 break;
926 case CDS_DISC_OK:
927 case CDS_NO_DISC:
928 #ifdef HAVE_LIBXOSD
929 if ( osd )
930 {
931 xosd_display(osd, 0, XOSD_string, "Eject");
932 xosd_display(osd, 1, XOSD_string, "");
933 }
934 #endif
935 if ( (ioctl(fd, CDROMEJECT)) != 0 ) {
936 SYSLOG( LOG_NOTICE, "CDROMEJECT failed: %s\n",
937 strerror(errno) );
938 }
939 break;
940 case CDS_NO_INFO:
941 case CDS_DRIVE_NOT_READY:
942 default:
943 || Ignore ||
944 break;
945 }
946 close(fd);
947 return 0;
948 }
949 else
950 {
951 SYSLOG(LOG_NOTICE, "CDROM_DRIVE_STATUS failed: %s\n", strerror(errno));
952 return -1;
953 }
954 End Andy *****/
955 }
956
957
958 static int
959 launchApp(int keycode)
960 {
961 int pid;
962 char* type = NULL;
963 int i;
964
965 /* Given the keycode, we find the string corresponding to it */
966 for ( i = 0; i < NUM_PREDEF_HOTKEYS; i++ )
967 {
968 if ( keycode == (kbd.defCmds)[i].key )
969 {
970 type = defStr[i].name;
971 break;
972 }
973 }
974 if ( type == NULL )
975 return -1; /* this keycode is not associated with any app */
976
977 if ( (pid=fork2()) == -1 )
978 {
979 uInfo("Cannot launch the %s\n", type);
980 }
981 else if ( pid == 0 )
982 {
983 /* Construct the argument arrays */
984 char** arg_array;
985 char* c = getConfig(type);
986 char* cc;
987 int noOfArgs = 1; /* including the NULL element */
988 int i = 0;
989 do {
990 c = strchr( c+1, ' ' );
991 noOfArgs++;
992 } while ( c != NULL );
993 arg_array = XMALLOC( char*, noOfArgs );
994 /* dup needed since strtok modifies the string */
995 c = (char*) xstrdup( getConfig(type) );
996 cc = c; /* for free() */
997 arg_array[0] = strtok( c, " " );
998 while ( arg_array[i] != NULL )
999 {
1000 i++;
1001 arg_array[i] = strtok( NULL, " " );
1002 }
1003
1004 if ( execvp(arg_array[0], arg_array) == -1 )
1005 {
1006 uError("Cannot launch %s", type);
1007 XFREE(cc);
1008 XFREE(arg_array);
1009 _exit(-1);
1010 }
1011 }
1012 else
1013 {
1014 #ifdef HAVE_LIBXOSD
1015 if ( osd )
1016 {
1017 xosd_display(osd, 0, XOSD_string, type);
1018 xosd_display(osd, 1, XOSD_string, "");
1019 }
1020 #endif
1021 }
1022
1023 return 0;
1024 }
1025
1026
1027 int
1028 sleepState(int mode)
1029 {
1030 /***** Andy: No APM support
1031 #ifdef USE_APMD
1032 switch (mode)
1033 {
1034 // case SUSPEND:
1035 error = system("apm -s");
1036 break;
1037 // case STANDBY:
1038 error = system("apm -S");
1039 break;
1040 default:
1041 error = 0;
1042 break;
1043 }
1044 #else
1045 int fd;
1046 int error;
1047
1048 if ( (fd = apm_open()) < 0 )
1049 {
1050 uError("unable to open APM device");
1051 exit(1);
1052 }
1053 switch (mode)
1054 {
1055 // case SUSPEND:
1056 error = apm_suspend(fd);
1057 break;
1058 // case STANDBY:
1059 error = apm_standby(fd);
1060 break;
1061 default:
1062 error = 0;
1063 break;
1064 }
1065 apm_close(fd);
1066 #endif
1067 End Andy *****/
1068 /* USE_APMD */
1069 }
1070
1071
1072 static void
1073 lookupUserCmd(const int keycode)
1074 {
1075 int i;
1076
1077 for ( i = 0; i < kbd.noOfCustomCmds; i++ )
1078 {
1079 if ( kbd.customCmds[i].keycode == keycode )
1080 {
1081 int pid;
1082
1083 if ( (pid=fork2()) == -1 )
1084 {
1085 uInfo("Cannot launch \"%s\"\n", kbd.customCmds[i].desc);
1086 }
1087 else if ( pid == 0 )
1088 {
1089 /* Construct the argument arrays */
1090 char** arg_array;
1091 char* c = kbd.customCmds[i].command;
1092 char* cc;
1093 int noOfArgs = 1; /* including the NULL element */
1094 int j = 0;
1095 do {
1096 c = strchr( c+1, ' ' );
1097 noOfArgs++;
1098 } while ( c != NULL );
1099 arg_array = XMALLOC( char*, noOfArgs );
1100 /* dup needed since strtok modifies the string */
1101 c = (char*) xstrdup( kbd.customCmds[i].command );
1102 cc = c; /* cc is for free() later */
1103 arg_array[0] = strtok( c, " " );
1104 while ( arg_array[j] != NULL )
1105 {
1106 j++;
1107 arg_array[j] = strtok( NULL, " " );
1108 }
1109
1110 if ( execvp(arg_array[0], arg_array) == -1 )
1111 {
1112 uError("Cannot launch \"%s\"", kbd.customCmds[i].desc);
1113 XFREE(cc);
1114 XFREE(arg_array);
1115 _exit(-1);
1116 }
1117 }
1118 else
1119 {
1120 #ifdef HAVE_LIBXOSD
1121 if ( osd )
1122 {
1123 xosd_display(osd, 0, XOSD_string, kbd.customCmds[i].desc);
1124 xosd_display(osd, 1, XOSD_string, "");
1125 }
1126 #endif
1127 break; /* break the for loop */
1128 }
1129 }
1130 }
1131 }
1132
1133 /***====================================================================***/
1134
1135 #ifdef DEBUG
1136 static void
1137 printXkbActionMessage(FILE* file,XkbEvent* xkbev)
1138 {
1139 XkbActionMessageEvent *msg= &xkbev->message;
1140 SYSLOG( LOG_DEBUG, "message: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
1141 msg->message[0],msg->message[1],
1142 msg->message[2],msg->message[3],
1143 msg->message[4],msg->message[5]);
1144 SYSLOG( LOG_DEBUG, "key %d, event: %s, follows: %s\n",msg->keycode,
1145 (msg->press?"press":"release"),
1146 (msg->key_event_follows?"yes":"no"));
1147 return;
1148 }
1149 #endif
1150
1151
1152 void
1153 uError(char* s,...)
1154 {
1155 va_list ap;
1156
1157 va_start(ap, s);
1158 fprintf(errorFile,"%s: ", progname);
1159 vfprintf(errorFile,s,ap);
1160 fprintf(errorFile,": %s\n", strerror(errno));
1161 fflush(errorFile);
1162 va_end(ap);
1163 return;
1164 }
1165
1166 void
1167 uInfo(char* s,...)
1168 {
1169 va_list ap;
1170
1171 va_start(ap, s);
1172 fprintf(errorFile,"%s: ", progname);
1173 vfprintf(errorFile,s,ap);
1174 fflush(errorFile);
1175 va_end(ap);
1176 return;
1177 }
1178
1179 void
1180 uInternalError(char* s,...)
1181 {
1182 va_list ap;
1183
1184 va_start(ap, s);
1185 fprintf(errorFile,"%s: internal error: ", progname);
1186 vfprintf(errorFile,s,ap);
1187 fflush(errorFile);
1188 va_end(ap);
1189 return;
1190 }
1191
1192
1193 /*
1194 * Test whether filename is readable
1195 */
1196 int
1197 testReadable(const char* filename)
1198 {
1199 int fd;
1200
1201 if ( (fd = open(filename, O_RDONLY)) == -1 )
1202 {
1203 return 0;
1204 }
1205 else
1206 {
1207 close(fd);
1208 return 1;
1209 }
1210 }
1211
1212 /***====================================================================***/
1213 static int dummy() { /* grin */ }
1214
1215 #include <X11/Xlibint.h>
1216 static int
1217 dummyHandler(Display* d, XErrorEvent* ev)
1218 {
1219 /* Code below is mainly from the function XmuPrintDefaultErrorMessage */
1220
1221 _XExtension *ext = (_XExtension *)NULL;
1222 char major_op[128];
1223 char minor_op[128];
1224 char mesg[128];
1225
1226 /* Get string of Major and Minor opcode */
1227 /* XXX this is non-portable */
1228 for (ext = d->ext_procs;
1229 ext && (ext->codes.major_opcode != ev->request_code);
1230 ext = ext->next)
1231 ;
1232 if (ext)
1233 XmuSnprintf(major_op, sizeof(major_op), "%s", ext->name);
1234 else
1235 major_op[0] = '\0';
1236
1237 XmuSnprintf(mesg, sizeof(mesg),
1238 "%s.%d", ext->name, ev->minor_code);
1239 XGetErrorDatabaseText(dpy, "XRequest", mesg, "", minor_op, BUFSIZ);
1240
1241
1242 if ( d == dpy && ev->error_code == BadValue &&
1243 strncmp( major_op, "XKEYBOARD", 9 ) == 0 &&
1244 strncmp( minor_op, "XkbSetMap", 9 ) == 0
1245 #if 0
1246 ev->request_code == 149 /* XKEYBOARD */ &&
1247 ev->minor_code == 9 /* XkbSetMap */
1248 #endif
1249 )
1250 {
1251 dummyErrFlag = True;
1252 SYSLOG( LOG_DEBUG, "X BadValue Error" );
1253 }
1254 else
1255 {
1256 XmuPrintDefaultErrorMessage(d, ev, stderr);
1257 uInfo("Program exiting...");
1258 bailout();
1259 }
1260 return 0;
1261 }
1262
1263 static void
1264 commitXKBChanges(int tcode)
1265 {
1266 XkbMapChangesRec mapChangeRec;
1267
1268 /* Commit the change back to the server */
1269 bzero(&mapChangeRec, sizeof(mapChangeRec));
1270 mapChangeRec.changed = XkbKeySymsMask | XkbKeyTypesMask;
1271 mapChangeRec.first_key_sym = tcode;
1272 mapChangeRec.num_key_syms = 1;
1273 // mapChangeRec.first_key_act = tcode;
1274 // mapChangeRec.num_key_acts = 1;
1275 mapChangeRec.first_type = 0;
1276 mapChangeRec.num_types = xkb->map->num_types;
1277 if ( XkbChangeMap(dpy, xkb, &mapChangeRec) )
1278 {
1279 #ifdef DEBUG
1280 printf("map changed done: %d\n",tcode);
1281 #endif
1282 }
1283 else
1284 {
1285 uError("map changed failed\n"); bailout();
1286 }
1287 }
1288
1289 void
1290 initializeX(char* prg)
1291 {
1292 KeySym newKS;
1293 XkbMessageAction xma;
1294 XkbMapChangesRec mapChangeRec;
1295 int types[1];
1296 int i;
1297 int tcode;
1298
1299 dpy = GetDisplay(prg, dpyName, &xkbOpcode, &xkbEventCode);
1300 if (!dpy)
1301 bailout();
1302 /* This function is NECESSARY to prevent the X BadValue error
1303 * when running in Synchronize mode */
1304 XSetAfterFunction(dpy, dummy);
1305 XSetErrorHandler(dummyHandler);
1306
1307 /* Construct the Message Action struct */
1308 xma.type = XkbSA_ActionMessage;
1309 xma.flags = XkbSA_MessageOnPress;
1310 strcpy(xma.message," ");
1311
1312 #if 0
1313 #ifdef DEBUG
1314 SYSLOG( LOG_DEBUG, "num_acts:%d size_acts:%d",
1315 xkb->server->num_acts, xkb->server->size_acts );
1316 #endif
1317 #endif
1318
1319 /* Add KeySym to the key codes, as they don't have any KeySyms before */
1320 for ( i = 0; i < NUM_PREDEF_HOTKEYS + kbd.noOfCustomCmds; i++ )
1321 {
1322 if ( i < NUM_PREDEF_HOTKEYS )
1323 {
1324 tcode = (kbd.defCmds)[i].key;
1325 newKS = (kbd.defCmds)[i].keysym;
1326 if ( tcode == 0 )
1327 continue;
1328 }
1329 else
1330 {
1331 tcode = kbd.customCmds[i-NUM_PREDEF_HOTKEYS].keycode;
1332 newKS = kbd.customCmds[i-NUM_PREDEF_HOTKEYS].keysym;
1333 }
1334 #if 0
1335 xkb= XkbGetKeyboard(dpy,XkbGBN_AllComponentsMask,XkbUseCoreKbd);
1336 xkb= XkbGetKeyboard(dpy,XkbAllComponentsMask,XkbUseCoreKbd);
1337 #endif
1338 xkb = XkbGetMap(dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
1339 if (!xkb)
1340 {
1341 uError("XkbGetMap failed\n"); bailout();
1342 }
1343
1344 /* Check the keycode range */
1345 if ( ! XkbKeycodeInRange(xkb, tcode) )
1346 {
1347 uInfo("The keycode %d cannot be used, as it's not between the min(%d) and max(%d) keycode of your keyboard.\n"
1348 "Please increase the 'maximum' value in /usr/X11R6/lib/X11/xkb/keycodes/xfree86, then restart X.",
1349 tcode, xkb-> min_key_code, xkb->max_key_code);
1350 continue;
1351 }
1352
1353 /* Assign a group to the key code */
1354 types[0] = XkbOneLevelIndex;
1355 if ( XkbChangeTypesOfKey(xkb, tcode, 1, XkbGroup1Mask, types, NULL)
1356 != Success )
1357 {
1358 uError("XkbChangeTypesOfKey failed"); bailout();
1359 }
1360 /*
1361 types[XkbGroup1Index] = XkbKeyTypeIndex( xkb, code, XkbGroup1Index );
1362 */
1363
1364 /* Change their Keysyms */
1365 if ( XkbResizeKeySyms( xkb, tcode, 1 ) == NULL )
1366 {
1367 uInfo("resize keysym failed\n"); bailout();
1368 }
1369 /* Assign a new keysym to the key code. According to
1370 * XF86keysym.h, the vendor specific XFree86 keysym range is
1371 * 0x1008FF01 to 0x1008FFFF. So I just assign keysyms to the
1372 * internet keys starting from 0x1008FF01. I think it doesn't
1373 * really matter to which one I use for the moment. For the
1374 * exact keysyms, please refer to XKeysymDB, */
1375 // newKS = 0x1008FF01 + tcode;
1376 *XkbKeySymsPtr(xkb,tcode) = newKS;
1377
1378 #if 0
1379 printf("keycode %d owns keysym %x\n", tcode,newKS);
1380 XChangeKeyboardMapping(dpy, tcode, 1, &newKS, 1);
1381 #endif
1382
1383 /* Add one key action to it */
1384 if ( XkbResizeKeyActions( xkb, tcode, 1 ) == NULL )
1385 {
1386 uInfo("resize key action failed\n"); bailout();
1387 }
1388
1389 commitXKBChanges(tcode);
1390 commitXKBChanges(tcode); /* YES, we need to call it twice! */
1391
1392 /* Assign the Message Action to the key code */
1393 (&(xkb->server->acts[ xkb->server->key_acts[tcode] ]))[0] = (XkbAction) xma;
1394
1395 /* Commit the change back to the server. Yeah we need to do it
1396 * here instead of in commit XKBChanges(). Strange, eh? But
1397 * you just can't, I wonder what the fsck X is doing. I get
1398 * this just by lots of trial-and-error and many nights of no
1399 * sleeping to trace X with gdb. */
1400 bzero(&mapChangeRec, sizeof(mapChangeRec));
1401 mapChangeRec.changed = XkbKeyActionsMask;
1402 mapChangeRec.first_key_act = tcode;
1403 mapChangeRec.num_key_acts = 1;
1404 if ( XkbChangeMap(dpy, xkb, &mapChangeRec) )
1405 {
1406 #ifdef DEBUG
1407 printf("map changed done: %d\n",tcode);
1408 #endif
1409 }
1410 else
1411 {
1412 uError("map changed failed\n"); bailout();
1413 }
1414 #if 0
1415 #ifdef DEBUG
1416 SYSLOG( LOG_DEBUG, "idx:%d has action:%d no.:%d noOfGrps:%d\n",
1417 xkb->server->key_acts[tcode], XkbKeyHasActions(xkb,tcode),
1418 XkbKeyNumActions(xkb,tcode), XkbKeyNumGroups(xkb,tcode) );
1419 SYSLOG( LOG_DEBUG, "keycode %d\nbefore: %d",
1420 tcode, XkbKeyActionsPtr(xkb,tcode)[0].type);
1421 #endif
1422
1423 // xkb = XkbGetMap(dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
1424 #ifdef DEBUG
1425 SYSLOG( LOG_DEBUG, "after: %d",XkbKeyActionsPtr(xkb,tcode)[0].type);
1426 #endif
1427 #endif
1428
1429 if ( dummyErrFlag ) /* dummyHandler() have set it */
1430 {
1431 i--; /* need to redo this round, as the action message
1432 was not assigned to this keysym */
1433 dummyErrFlag == False;
1434 }
1435 }
1436
1437 /* Select the ActionMessage event in any circumstances */
1438 if ( !XkbSelectEvents( dpy, XkbUseCoreKbd, XkbActionMessageMask,
1439 XkbActionMessageMask ))
1440 {
1441 uInfo("Couldn't select desired XKB events\n");
1442 bailout();
1443 }
1444 }
1445
1446 /* Initialize XOSD */
1447 void
1448 initXOSD(void)
1449 {
1450 #ifdef HAVE_LIBXOSD
1451 if ( osd )
1452 {
1453 osd = xosd_create(3);
1454 xosd_set_pos(osd, strncmp(getConfig("osd_position"),"top",3)?XOSD_bottom:XOSD_top);
1455 xosd_set_bar_length(osd, atoi(getConfig("osd_bar_length")));
1456 xosd_set_colour(osd, xstrdup(getConfig("osd_color")));
1457 xosd_set_shadow_colour(osd, xstrdup(getConfig("osd_shadow_color")));
1458 xosd_set_shadow_offset(osd, atoi(getConfig("osd_shadow_offset")));
1459 xosd_set_horizontal_offset(osd, atoi(getConfig("osd_hoffset")));
1460 xosd_set_vertical_offset(osd, atoi(getConfig("osd_voffset")));
1461 xosd_set_font(osd, xstrdup(getConfig("osd_font")));
1462 xosd_set_align(osd, strncmp(getConfig("osd_align"),"left",4)?((!strncmp(getConfig("osd_align"),"center",6))?XOSD_center:XOSD_right):XOSD_left);
1463 }
1464 #endif
1465 }
1466
1467
1468 /* fork2() -- like fork, but the new process is immediately orphaned
1469 * (won't leave a zombie when it exits)
1470 * Returns 1 to the parent, not any meaningful pid.
1471 * The parent cannot wait() for the new process (it's unrelated).
1472 */
1473
1474 /* This version assumes that you *haven't* caught or ignored SIGCHLD. */
1475 /* If you have, then you should just be using fork() instead anyway. */
1476
1477 /* fork2() is from the Unix Programming FAQ */
1478 int
1479 fork2(void)
1480 {
1481 pid_t pid;
1482 int rc;
1483 int status;
1484
1485 if (!(pid = fork()))
1486 {
1487 switch (fork())
1488 {
1489 case 0: return 0;
1490 case -1: _exit(errno); /* assumes all errnos are <256 */
1491 default: _exit(0);
1492 }
1493 }
1494
1495 if (pid < 0 || waitpid(pid,&status,0) < 0)
1496 return -1;
1497
1498 if (WIFEXITED(status))
1499 if (WEXITSTATUS(status) == 0)
1500 return 1;
1501 else
1502 errno = WEXITSTATUS(status);
1503 else
1504 errno = EINTR; /* well, sort of :-) */
1505
1506 return -1;
1507 }
1508
1509 int
1510 main(int argc, char *argv[])
1511 {
1512 XkbEvent ev;
1513 int i, k;
1514
1515 errorFile = stderr;
1516 openlog( PACKAGE, LOG_CONS | LOG_PID, LOG_USER );
1517
1518 readConfigFile();
1519
1520 /* initialize the kbd variable */
1521 kbd.noOfCustomCmds = 0;
1522 kbd.defCmds = XCALLOC( defEntry, NUM_PREDEF_HOTKEYS );
1523
1524 if ( !parseArgs(argc,argv) )
1525 bailout();
1526
1527 #if HAVE_GTK
1528 if ( !noSplash )
1529 {
1530 int pid;
1531
1532 if ( (pid=fork2()) == -1 )
1533 {
1534 uInfo("Cannot spawn new process\n");
1535 }
1536 else if ( pid == 0 )
1537 {
1538 gtk_init(&argc,&argv);
1539 splash_create (SPLASH_IMAGE, 2000); /* show splash for 2 sec */
1540 gtk_main();
1541 }
1542 }
1543 #endif /* HAVE_GTK */
1544
1545 if (background)
1546 {
1547
1548 if ( fork() !=0 )
1549 {
1550 SYSLOG( LOG_NOTICE, "Running in the background");
1551 _exit(0);
1552 }
1553 else
1554 {
1555 chdir("/");
1556 }
1557 }
1558
1559 initializeX(argv[0]);
1560 #ifdef HAVE_LIBXOSD
1561 initXOSD();
1562 #endif
1563
1564 #if HAVE_GTK
1565 if ( noSplash )
1566 #endif
1567 printf( "%s started successfully.\n", progname );
1568
1569 /* Process the events in a forever loop */
1570 while (1)
1571 {
1572 XNextEvent( dpy, &ev.core );
1573 #ifdef DEBUG
1574 printXkbActionMessage( stdout, &ev );
1575 #endif
1576 if ( ev.type == xkbEventCode+XkbEventCode &&
1577 ev.any.xkb_type == XkbActionMessage )
1578 {
1579 SYSLOG( LOG_INFO, "Keycode %d pressed\n", ev.message.keycode );
1580
1581 #ifdef HAVE_LIBXOSD
1582 if (osd)
1583 xosd_set_timeout(osd, atoi(getConfig("osd_timeout")));
1584 #endif
1585 if ( keytypes[ev.message.keycode] == 1 )
1586 {
1587 /* Apps stuffs */
1588 launchApp(ev.message.keycode);
1589 } else
1590 /* Sound stuffs */
1591 if ( ev.message.keycode == (kbd.defCmds)[ejectKey].key )
1592 {
1593 /* Use thread to improve the responsiveness */
1594 pthread_t tp;
1595 pthread_attr_t attr;
1596
1597 pthread_attr_init(&attr);
1598 pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
1599 pthread_create (&tp, &attr, ejectDisc, NULL);
1600 } else
1601 if ( ev.message.keycode == (kbd.defCmds)[volUpKey].key ) {
1602 adjustVol(volUpAdj);
1603 } else
1604 if ( ev.message.keycode == (kbd.defCmds)[volDownKey].key ) {
1605 adjustVol(volDownAdj);
1606 } else
1607 if ( ev.message.keycode == (kbd.defCmds)[muteKey].key ) {
1608 doMute();
1609 } else
1610 /* APM stuffs */
1611 /**** Andy: No APM support
1612 if ( ev.message.keycode == (kbd.defCmds)[sleepKey].key ||
1613 ev.message.keycode == (kbd.defCmds)[wakeupKey].key ) {
1614 sleepState(STANDBY);
1615 } else
1616 if ( ev.message.keycode == (kbd.defCmds)[powerDownKey].key ) {
1617 sleepState(SUSPEND);
1618 }
1619 else
1620 {
1621 End Andy *****/
1622 lookupUserCmd(ev.message.keycode); /* User-defined stuffs */
1623 //Andy }
1624 }
1625 }
1626
1627 #ifdef HAVE_LIBXOSD
1628 if (osd)
1629 xosd_destroy(osd);
1630 #endif
1631 XCloseDisplay(dpy);
1632 closelog();
1633 return 0;
1634 }
1635