wmail: use continue instead of goto.
[dockapps.git] / wmtv / src / wmtv.c
blob1fa2eea9f5a8d4879997c286b9601d229aaca204
1 /* Copyright (c) 1999 Wee Liang (wliang@tartarus.uwa.edu.au)
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program (see the file COPYING); if not, write to the
15 * Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /* Includes */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <getopt.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <time.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 #include <libv4l1-videodev.h>
38 #include <linux/soundcard.h>
40 #include <X11/Xlib.h>
41 #include <X11/Xutil.h>
42 #include <X11/Xmd.h>
43 #include <X11/StringDefs.h>
44 #include <X11/keysym.h>
45 #include <X11/xpm.h>
46 #include <X11/extensions/shape.h>
47 #include <X11/extensions/Xxf86dga.h>
48 #include <X11/extensions/xf86vmode.h>
50 #include "wmgeneral/wmgeneral.h"
51 #include "wmtv-master.xpm"
52 #include "channels.h"
55 /* Defines */
56 #define ON 1
57 #define OFF 0
59 #define NTFB 0 /* On/SetTune/Off Button */
60 #define SCANLB 1 /* Scan Left Button */
61 #define SCANRB 2 /* Scan Right Button */
62 #define FULLSB 3 /* Full Screen Toggle Button */
64 #ifndef TRUE
65 #define TRUE 1
66 #endif
67 #ifndef FALSE
68 #define FALSE 0
69 #endif
71 #define SETON 0
72 #define SETOFF 1
73 #define SETUNE 2
74 #define SETSPD 3
76 #define MAXCHAN 99
77 #define OPTIONS "hvd:g:e:b:c:"
79 #define TELEVISION 0
80 #define COMPOSITE 1
81 #define SVIDEO 2
83 #ifndef GLOBALCONFFILE
84 #define GLOBALCONFFILE "/etc/wmtvrc"
85 #endif
87 /* Global Variables */
88 int tfd;
89 int card_present = FALSE;
90 int ntfb_status = SETOFF;
91 char *maxpreset = NULL;
92 char **chan = NULL;
93 int mode_present = FALSE;
95 int chn = 0;
96 int aud = 0;
97 int tpst = 0;
98 int cchannel = 0;
99 int timebutton = 0;
100 int tvsource = 0;
101 int ccapt;
102 int norcfile = 0;
103 int ic = 0;
104 int cnotune = 0;
105 int vsource = 0;
106 int isource = 0;
107 int compchannel = 0;
108 int vidmode = 0;
109 int fmode = 0;
110 int mute = 0;
111 int dcret;
112 int tml;
113 int fswidth = 0;
114 int fsheight = 0;
115 pid_t child_pid = -1;
116 int restart = FALSE;
118 unsigned long ccrfreq;
119 unsigned long rfreq;
120 unsigned long st;
122 char *norm = NULL;
123 char *source;
124 char *mode = NULL;
125 char *fullscreen = NULL;
126 int freqnorm = -1;
127 char *cname[MAXCHAN];
128 char *comment[MAXCHAN];
129 long ftune[MAXCHAN];
130 char *progname;
131 char *dev = "/dev/video";
133 char *sysConfFile = GLOBALCONFFILE;
134 char *usrConfFile;
136 int wmtv_mask_width = 64;
137 int wmtv_mask_height = 64;
138 char wmtv_mask_bits[64*64];
140 int btime = 0;
141 int but_pressed = FALSE;
142 int but_clicked = FALSE;
143 int maxpst;
144 int x_lc;
145 int y_lc;
146 Time t_lc;
148 rckeys wmtv_keys[] = {
149 { "freqnorm", &norm },
150 { "source", &source },
151 { "maxpreset", &maxpreset },
152 { "mode", &mode },
153 { "fullscreen", &fullscreen },
154 { NULL, NULL }
157 XEvent Event;
158 XWindowAttributes Winattr;
159 Window fmwin;
160 GC fmGC;
161 XF86VidModeModeInfo **modelines, *fullscreenmode = NULL;
162 XF86VidModeModeLine scmode;
164 struct video_capability vcap;
165 struct video_buffer vfb;
166 struct video_window vwin;
167 struct video_window vswin;
168 struct video_channel vchn, vchns;
169 struct video_picture vpic;
170 struct video_tuner vtun;
171 struct video_audio vaud;
172 struct video_mbuf vmbuf;
173 struct video_mmap vmmap;
174 struct video_clip vclip[2];
175 struct video_clip vclip2[2];
178 /* Function prototypes */
179 void TVOn(void);
180 void TVOff(void);
181 void TuneTV(void);
182 void ChanUp(void);
183 void ChanDown(void);
184 void FineTuneUp(void);
185 void FineTuneDown(void);
186 void ScanUp(void);
187 void ScanDown(void);
189 void ButtonUp(int);
190 void ButtonDown(int);
191 void Capture(void);
192 void MuteAudio(void);
193 void UnMuteAudio(void);
194 void VolumeUp(void);
195 void VolumeDown(void);
196 void DrawPresetChan(int);
197 void DoFullScreen(void);
198 void GetFrameBuffer(void);
199 void RetScreen(void);
200 void GrabImage(void);
202 void ParseRCFile(const char *, rckeys *);
203 void ParseRCFile2(const char *);
204 void WriteRCFile(const char *, rckeys *);
205 void InitConfig(void);
206 void InitPalette(void);
208 void Usage(void);
209 void Version(void);
211 void
212 sigchld_handler(int i)
214 pid_t pid;
215 pid = waitpid((pid_t)-1, NULL, WNOHANG);
216 while (pid>(pid_t)0) {
217 if (pid == child_pid) {
218 child_pid = -1;
219 restart = TRUE;
221 pid = waitpid((pid_t)-1, NULL, WNOHANG);
225 void
226 init_signal()
228 struct sigaction sa;
230 sa.sa_handler = &sigchld_handler;
231 sigemptyset(&sa.sa_mask);
232 sa.sa_flags = SA_RESTART;
233 sigaction(SIGCHLD, &sa, NULL);
236 char *
237 expand_format(char *format, char *letters, char **expansions)
239 char *string;
240 unsigned int string_pos = 0;
241 unsigned int size;
242 size = strlen(format)+1;
243 string = (char *)malloc(size*sizeof(char));
244 for (; *format != '\0'; format++) {
245 if (*format == '%') {
246 format++;
247 if (*format != '%') {
248 unsigned int i;
249 for (i = 0; letters[i] != '\0'; i++) {
250 if (letters[i] == *format)
251 break;
253 if (letters[i] != '\0') {
254 unsigned int expansion_size;
255 expansion_size = strlen(expansions[i]);
256 while (string_pos+expansion_size+1 > size) {
257 size *= 2;
258 string = realloc(string, size*sizeof(char));
260 memcpy(string+string_pos, expansions[i], expansion_size);
261 string_pos += expansion_size;
262 continue;
264 else {
265 format--;
269 while (string_pos+1+1 > size) {
270 size *= 2;
271 string = realloc(string, size*sizeof(char));
273 string[string_pos] = *format;
274 string_pos++;
276 string[string_pos] = '\0';
277 return string;
280 /* main function */
282 main(int argc, char *argv[])
284 int c, opind;
285 int pressed_button = -1;
286 /* pid_t pid; */
287 static struct option long_options[] = {
288 {"device", 1, 0, 'c'},
289 {"display", 1, 0, 'd'},
290 {"geometry", 1, 0, 'g'},
291 {"bpp", 1, 0, 'b'},
292 {"exe", 1, 0, 'e'},
293 {"help", 0, 0, 'h'},
294 {"version", 0, 0, 'v'},
295 {0, 0, 0, 0}
298 progname = strdup(argv[0]);
301 char *home = getenv("HOME");
303 if (home == NULL) {
304 fprintf(stderr, "wmtv: $HOME should be set.\n");
305 exit(1);
308 usrConfFile = (char *)malloc(sizeof(char)*(strlen(home)+8+1));
309 strcpy(usrConfFile, home);
310 strcat(usrConfFile, "/.wmtvrc");
313 while (1) {
314 opind = 0;
315 c = getopt_long (argc, argv, OPTIONS, long_options, &opind);
316 if (c == -1)
317 break;
319 switch(c)
321 case 0:
323 fprintf(stderr, "wmtv: option - %s", long_options[opind].name);
324 if (optarg)
325 fprintf(stderr, " with arg %s", optarg);
326 printf("\n");
328 break;
329 case 'd':
330 display_name = strdup(optarg);
331 break;
332 case 'g':
333 geometry = strdup(optarg);
334 break;
335 case 'e':
336 exe = strdup(optarg);
337 /* strcat(exe, " &"); */
338 break;
339 case 'c':
340 dev = strdup(optarg);
341 break;
342 case 'b':
343 fprintf(stderr, "wmtv: option not implemented yet\n");
344 Usage();
345 exit(1);
346 break;
347 case 'v':
348 Version();
349 exit(0);
350 break;
351 default:
352 Usage();
353 exit(1);
357 /* creat windows */
358 createXBMfromXPM (wmtv_mask_bits, wmtv_master_xpm,
359 wmtv_mask_width, wmtv_mask_height);
360 openXwindow (argc, argv, wmtv_master_xpm, wmtv_mask_bits,
361 wmtv_mask_width, wmtv_mask_height);
363 AddMouseRegion (NTFB, 47, 48, 59, 59); /* On/SetTune/Off Button */
364 AddMouseRegion (SCANLB, 23, 48, 35, 59); /* Left Preset/Scan Button */
365 AddMouseRegion (SCANRB, 35, 48, 47, 59); /* Right Preset/Scan Button */
366 AddMouseRegion (FULLSB, 5, 5, 59, 44); /* Toggle FullScreen */
368 init_signal();
370 /* wmtv main loop */
371 while (1)
373 if (restart) {
374 TVOn();
375 if (ntfb_status == SETOFF) {
376 ntfb_status = SETON;
377 RedrawWindow();
378 XFlush(display);
380 restart = FALSE;
381 continue;
383 while (XPending(display))
385 XNextEvent(display, &Event);
386 switch (Event.type) {
387 case Expose:
388 RedrawWindow();
389 break;
390 case DestroyNotify:
391 XCloseDisplay(display);
392 ccapt = 0;
393 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
394 perror("ioctl VIDIOCCAPTURE");
396 close(tfd);
397 usleep(50000L);
398 exit(0);
399 break;
400 case ButtonPress:
401 if ((Event.xany.window == fmwin) && fmode) {
402 RetScreen();
404 else {
405 pressed_button = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
406 switch (pressed_button) {
407 case NTFB:
408 ButtonDown(NTFB);
409 t_lc = Event.xbutton.time;
410 but_pressed = TRUE;
411 break;
412 case SCANLB:
413 ButtonDown(SCANLB);
414 if (ntfb_status == SETUNE) {
415 switch (Event.xbutton.button) {
416 case 1:
417 timebutton = 1;
418 while (timebutton == 1)
419 if (isource == TELEVISION)
420 ScanDown();
421 break;
422 case 3:
423 if (isource == TELEVISION)
424 FineTuneDown();
425 break;
428 else if (ntfb_status == SETON)
429 ChanDown();
430 break;
431 case SCANRB:
432 ButtonDown(SCANRB);
433 if (ntfb_status == SETUNE) {
434 switch (Event.xbutton.button) {
435 case 1:
436 timebutton = 1;
437 while (timebutton)
438 if (isource == TELEVISION)
439 ScanUp();
440 break;
441 case 3:
442 if (isource == TELEVISION)
443 FineTuneUp();
444 break;
447 else if (ntfb_status == SETON)
448 ChanUp();
449 break;
450 case FULLSB:
451 ButtonDown(FULLSB);
452 switch (Event.xbutton.button) {
453 case 1:
454 but_pressed = TRUE;
455 break;
456 case 2:
457 but_pressed = TRUE;
458 break;
459 case 3:
460 if (!mute) {
461 MuteAudio();
463 else {
464 UnMuteAudio();
466 break;
468 break;
470 RedrawWindow();
472 break;
473 case ButtonRelease:
474 switch (pressed_button) {
475 case NTFB:
476 ButtonUp(NTFB);
477 if (but_pressed) {
478 if (Event.xbutton.time - t_lc >= 900) {
479 btime = TRUE;
480 but_pressed = FALSE;
484 if (ntfb_status == SETOFF) {
485 if (child_pid == -1) {
486 ntfb_status = SETON;
487 TVOn();
490 else if (ntfb_status == SETON) {
491 if (!btime) {
492 ntfb_status = SETUNE;
493 copyXPMArea(96, 79, 11, 7, 6, 50);
494 RedrawWindowXYWH(6, 50, 11, 7);
496 else if (btime) {
497 ntfb_status = SETOFF;
498 btime = FALSE;
499 ic = TRUE;
500 TVOff();
503 else if (ntfb_status == SETUNE) {
504 if (!btime) {
505 ftune[cchannel] = (rfreq - ccrfreq);
506 /* fprintf(stderr, "wmtv: finetune offset = %ld\n", ftune[cchannel]); */
507 WriteRCFile(usrConfFile, wmtv_keys);
508 ntfb_status = SETON;
509 DrawPresetChan(cchannel);
511 else if (btime) {
512 ntfb_status = SETOFF;
513 btime = FALSE;
514 ic = TRUE;
515 TVOff();
518 break;
519 case SCANLB:
520 ButtonUp(SCANLB);
521 if (ntfb_status == SETUNE)
522 timebutton = 0;
523 break;
524 case SCANRB:
525 ButtonUp(SCANRB);
526 if (ntfb_status == SETUNE)
527 timebutton = 0;
528 break;
529 case FULLSB:
530 ButtonUp(FULLSB);
531 switch (Event.xbutton.button) {
532 case 1: {
533 if (but_clicked) {
534 but_pressed = FALSE;
535 but_clicked = FALSE;
537 if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
539 if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
540 if (exe) {
541 pid_t pid;
542 char *command;
543 char *letters = "#nf";
544 char *(expansions[3]);
545 ntfb_status = SETOFF;
546 TVOff();
547 expansions[0] = malloc(3*sizeof(char));
548 snprintf(expansions[0], 3, "%d", cchannel+1);
549 expansions[1] = comment[cchannel];
550 expansions[2] = malloc(15*sizeof(char));
551 snprintf(expansions[2], 15, "%.3f", (double)rfreq/(double)st);
552 command = expand_format(exe, letters, expansions);
553 /* system(exe); */
554 child_pid = fork();
555 if (child_pid == (pid_t) 0) {
556 char *argv[4];
557 argv[0] = "sh";
558 argv[1] = "-c";
559 argv[2] = command;
560 argv[3] = NULL;
561 execv("/bin/sh", argv);
562 exit(-1);
564 free(expansions[0]);
565 free(expansions[2]);
566 free(command);
567 pid = waitpid(child_pid, NULL, WNOHANG);
568 if (pid != 0) {
569 child_pid = -1;
570 restart = TRUE;
572 /* printf("Returned pid:\n"); */
574 #if 0
575 pid = fork();
577 /* child */
578 if (pid == (pid_t) 0) {
579 execlp("xawtv", "xawtv", "&", (char *) 0);
582 else if (pid < (pid_t) 0) {
583 perror("fork");
586 /* parent */
587 else {
588 if (waitpid(pid, NULL, 0) < 0) {
589 perror("waitpid");
590 #endif
592 else {
593 DoFullScreen();
599 if (but_pressed) {
600 t_lc = Event.xbutton.time;
601 x_lc = Event.xbutton.x;
602 y_lc = Event.xbutton.y;
603 but_clicked = TRUE;
604 but_pressed = FALSE;
607 break;
608 case 2: {
609 if (but_clicked) {
610 but_pressed = FALSE;
611 but_clicked = FALSE;
613 if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
615 if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
616 DoFullScreen();
621 if (but_pressed) {
622 t_lc = Event.xbutton.time;
623 x_lc = Event.xbutton.x;
624 y_lc = Event.xbutton.y;
625 but_clicked = TRUE;
626 but_pressed = FALSE;
629 break;
630 case 3:
631 break;
633 break;
635 RedrawWindow();
636 break;
637 case VisibilityNotify:
638 switch(Event.xvisibility.state) {
639 case VisibilityFullyObscured:
640 ccapt = 0;
641 if (tfd && (ntfb_status != SETOFF) && !fmode) {
642 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
643 perror("ioctl VIDIOCCAPTURE");
646 break;
647 case VisibilityPartiallyObscured:
648 ccapt = 0;
649 if (tfd && (ntfb_status != SETOFF) && !fmode) {
650 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
651 perror("ioctl VIDIOCCAPTURE");
654 break;
655 case VisibilityUnobscured:
656 ccapt = 1;
657 if (tfd && (ntfb_status != SETOFF) && !fmode) {
658 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
659 perror("ioctl VIDIOCCAPTURE");
662 break;
664 RedrawWindow();
665 break;
666 case KeyPress:
667 if ((Event.xany.window == fmwin) && fmode) {
668 switch(XKeycodeToKeysym(display, Event.xkey.keycode, 0)) {
669 case XK_Up:
670 if (isource == TELEVISION)
671 ChanUp();
672 break;
673 case XK_Down:
674 if (isource == TELEVISION)
675 ChanDown();
676 break;
677 case XK_Right:
678 VolumeUp();
679 break;
680 case XK_Left:
681 VolumeDown();
682 break;
683 case XK_m:
684 if (!mute) {
685 MuteAudio();
687 else {
688 UnMuteAudio();
690 break;
691 case XK_Escape:
692 RetScreen();
693 break;
694 default:
695 break;
698 default:
699 break;
701 XFlush(display);
703 usleep(50000L);
705 return(0);
709 /* ButtonDown function */
710 void
711 ButtonDown(int button)
713 switch (button) {
714 case NTFB:
715 copyXPMArea(79, 100, 12, 11, 47, 48);
716 RedrawWindowXYWH (47, 48, 12, 11);
717 break;
718 case SCANLB:
719 copyXPMArea(55, 100, 12, 11, 23, 48);
720 RedrawWindowXYWH(35, 48, 12, 11);
721 break;
722 case SCANRB:
723 copyXPMArea(67, 100, 12, 11, 35, 48);
724 RedrawWindowXYWH(35, 48, 12, 11);
725 break;
726 case FULLSB:
727 break;
732 /* ButtonUp function */
733 void
734 ButtonUp(int button)
736 switch (button) {
737 case NTFB:
738 copyXPMArea(79, 88, 12, 11, 47, 48);
739 RedrawWindowXYWH(47, 48, 12, 11);
740 break;
741 case SCANLB:
742 copyXPMArea(55, 88, 12, 11, 23, 48);
743 RedrawWindowXYWH(23, 48, 12, 11);
744 break;
745 case SCANRB:
746 copyXPMArea(67, 88, 12, 11, 35, 48);
747 RedrawWindowXYWH(35, 48, 12, 11);
748 break;
749 case FULLSB:
750 break;
755 /* TVOn function */
756 void
757 TVOn(void)
759 int i;
760 Window junkwin;
761 int rx, ry;
762 char *p;
764 XWindowAttributes winattr;
766 if (!XGetWindowAttributes (display, iconwin, &winattr)) {
767 fprintf(stderr, "wmtv: error getting winattr of iconwin\n");
770 if (!XTranslateCoordinates(display, iconwin, winattr.root,
771 -winattr.border_width,
772 -winattr.border_width,
773 &rx, &ry, &junkwin)) {
774 fprintf(stderr, "wmtv: error translating coordinates\n");
777 /* This part was taken from xawtv's source code */
778 switch (system("v4l-conf -q")) {
779 case -1: /* can't run */
780 fprintf(stderr,"could'nt start v4l-conf\n");
781 break;
782 case 0: /* ok */
783 break;
784 default: /* non-zero return */
785 fprintf(stderr,"v4l-conf had some trouble, "
786 "trying to continue anyway\n");
788 /* End of "stolen" part */
789 InitConfig();
790 GetFrameBuffer();
791 InitPalette();
793 ccapt = 1;
795 vwin.x = rx;
796 vwin.y = ry + 5;
798 vwin.width = 64;
799 vwin.height = 39;
801 vclip[0].x = 0; /* Clipping Rect 1 */
802 vclip[0].y = 0;
803 vclip[0].width = 5;
804 vclip[0].height = 39;
805 vclip[1].x = 59; /* Clipping Rect 2 */
806 vclip[1].y = 0;
807 vclip[1].width = 5;
808 vclip[1].height = 39;
810 vwin.clips = vclip;
811 vwin.clipcount = 2;
813 vchn.channel = tvsource;
814 vaud.audio = tvsource;
816 if (source) {
817 p = source;
818 if (*p == 'T')
819 isource = TELEVISION;
820 else if (*p == 'C') {
821 isource = COMPOSITE;
822 while (isalpha(*p))
823 ++p;
824 compchannel = atoi(p);
826 else if (*p == 'S')
827 isource = SVIDEO;
830 if (!cnotune) {
831 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0)
832 perror("ioctl VIDIOCGTUNER");
833 if (vtun.flags & VIDEO_TUNER_LOW)
834 st = 16000;
835 else
836 st = 16;
839 if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0)
840 perror("ioctl VIDIOCGCHAN");
842 if (vchn.flags & VIDEO_VC_AUDIO) {
843 if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0)
844 perror("ioctl VIDIOCGAUDIO");
847 if (vaud.flags & VIDEO_AUDIO_MUTE) {
848 vaud.flags &= ~VIDEO_AUDIO_MUTE; /* Unmute */
849 vaud.volume = 0xFFFF;
852 if (isource == TELEVISION) {
853 for (i=0; i < CHAN_ENTRIES; i++) {
854 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
855 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
856 ccrfreq = rfreq - ftune[cchannel];
857 break;
860 DrawPresetChan(cchannel);
862 else if (isource == COMPOSITE) {
863 DrawPresetChan(compchannel);
865 else if (isource == SVIDEO) {
866 DrawPresetChan(-1);
869 if (vchn.flags & VIDEO_VC_AUDIO) {
870 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
871 perror("ioctl VIDIOCSAUDIO");
875 if (ioctl(tfd, VIDIOCSCHAN, &vchn) < 0)
876 perror("ioctl VIDIOCSCHAN");
878 if (!cnotune) {
879 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
880 perror("ioctl VIDIOCSFREQ");
883 if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0)
884 perror("ioctl VIDIOCSWIN");
886 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
887 perror("ioctl VIDIOCCAPTURE");
891 /* TVOff function */
892 void
893 TVOff(void)
895 ccapt = 0;
897 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
898 perror("ioctl VIDIOCCAPTURE");
900 vaud.audio = tvsource;
901 vaud.volume = 0;
902 vaud.flags |= VIDEO_AUDIO_MUTE;
904 if (vchn.flags & VIDEO_VC_AUDIO) {
905 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
906 perror("ioctl VIDIOCSAUDIO");
909 close(tfd);
910 copyXPMArea(66, 79, 11, 7, 6, 50);
911 RedrawWindowXYWH(6, 50, 11, 7);
915 /* VolumeUp function */
916 void
917 VolumeUp(void)
919 if(vchn.flags & VIDEO_VC_AUDIO) {
920 if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
921 fprintf(stderr, "Warning: v4l device does not support volume control.\n");
922 else if (vaud.volume <= 0xEEEE) {
923 vaud.audio = tvsource;
924 vaud.volume += 0x1111;
925 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
926 perror("ioctl VIDIOCSAUDIO");
932 /* VoumeDown function */
933 void
934 VolumeDown(void)
936 if (vchn.flags & VIDEO_VC_AUDIO) {
937 if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
938 fprintf(stderr, "Warning: v4l device does not support volume control.\n");
939 else if (vaud.volume >= 0x1111) {
940 vaud.audio = tvsource;
941 vaud.volume -= 0x1111;
942 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
943 perror("ioctl VIDIOCSAUDIO");
948 /* MuteAudio function */
949 void
950 MuteAudio(void)
952 if (vchn.flags & VIDEO_VC_AUDIO) {
953 vaud.audio = tvsource;
954 /* vaud.volume = 0; */
955 vaud.flags |= VIDEO_AUDIO_MUTE;
956 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
957 perror("ioctl VIDIOCSAUDIO");
959 mute = TRUE;
963 /* UnMuteAudio function */
964 void
965 UnMuteAudio(void)
967 if ((vchn.flags & VIDEO_VC_AUDIO) && (vaud.flags & VIDEO_AUDIO_MUTE)) {
968 vaud.audio = tvsource;
969 /* vaud.volume = (0xFFFF/2)+1; */
970 vaud.flags &= ~VIDEO_AUDIO_MUTE;
971 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
972 perror("ioctl VIDIOCSAUDIO");
974 mute = FALSE;
978 /* ScanUp function */
979 void
980 ScanUp(void)
982 rfreq += 2;
983 usleep(50000L);
984 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
985 perror("ioctl VIDIOCSFREQ");
987 usleep(10000L);
988 vtun.tuner = 0;
989 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
990 perror("ioctl VIDIOCGTUNER");
992 if (vtun.signal == 0xFFFF) {
993 timebutton = 0;
999 /* ScanDown function */
1000 void
1001 ScanDown(void)
1003 rfreq -= 2;
1004 usleep(50000L);
1005 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
1006 perror("ioctl VIDIOCSFREQ");
1008 usleep(10000L);
1009 vtun.tuner = 0;
1010 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
1011 perror("ioctl VIDIOCGTUNER");
1013 if (vtun.signal == 0xFFFF) {
1014 timebutton = 0;
1019 /* FineTuneUp function */
1020 void
1021 FineTuneUp(void)
1023 rfreq += 1;
1024 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
1025 perror("ioctl VIDIOCSFREQ");
1030 /* FineTuneDown function */
1031 void
1032 FineTuneDown(void)
1034 rfreq -= 1;
1035 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
1036 perror("ioctl VIDIOCSFREQ");
1041 /* ChanUp function */
1042 void
1043 ChanUp(void)
1045 int i;
1046 if (cchannel < maxpst)
1047 ++cchannel;
1048 for (i=0; i < CHAN_ENTRIES; i++) {
1049 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
1050 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
1051 ccrfreq = rfreq - ftune[cchannel];
1052 break;
1056 DrawPresetChan(cchannel);
1057 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
1058 perror("ioctl VIDIOCSFREQ");
1062 /* ChanDown function */
1063 void
1064 ChanDown(void)
1066 int i;
1067 if (cchannel != 0)
1068 --cchannel;
1069 for (i=0; i < CHAN_ENTRIES; i++) {
1070 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
1071 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
1072 ccrfreq = rfreq - ftune[cchannel];
1073 break;
1077 DrawPresetChan(cchannel);
1078 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
1079 perror("ioctl VIDIOCSFREQ");
1083 /* DrawPresetChan function */
1084 void
1085 DrawPresetChan(int cchannel)
1087 char temp[10];
1088 char *p = temp;
1089 int j=0;
1090 int k=6;
1092 if (isource == TELEVISION) {
1093 sprintf(temp, "%02d", cchannel+1);
1095 if (*p == '0') {
1096 copyXPMArea(66, 79, 5, 7, k, 50);
1097 k += 6;
1098 j++;
1099 p++;
1101 while (j < 2) {
1102 copyXPMArea((*p-'0')*6 + 1, 79, 5, 7, k, 50);
1103 k += 6;
1104 p++;
1105 j++;
1109 else if (isource == COMPOSITE) {
1110 copyXPMArea (109, 79, 5, 7, 6, 50);
1111 copyXPMArea ((compchannel*6) + 1, 79, 5, 7, 12, 50);
1114 else if (isource == SVIDEO) {
1115 copyXPMArea(116, 79, 11, 7, 6, 50);
1118 RedrawWindowXYWH(6, 50, 11, 7);
1122 /* ParseRCFile function */
1123 void
1124 ParseRCFile(const char *filename, rckeys *keys)
1126 char *p;
1127 char temp[128];
1128 char *tokens = " =\t\n";
1129 FILE *fp;
1130 int key = 0;
1132 if ((fp = fopen(filename, "r")) == NULL) {
1133 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1134 norcfile = 1;
1135 return;
1137 norcfile = 0;
1138 while (fgets(temp, 128, fp)) {
1139 if (temp[0] != '\n') {
1140 p = strtok(temp, tokens);
1141 for (key=0; keys[key].label; key++) {
1142 if ((!strcmp(p, keys[key].label))) {
1143 p = strtok(NULL, tokens);
1144 free(*keys[key].var);
1145 *keys[key].var = strdup(p);
1146 break;
1151 fclose(fp);
1155 /* ParseRCFile2 function */
1156 void
1157 ParseRCFile2(const char *filename)
1159 int menu = FALSE;
1160 char temp[128], name[128];
1161 FILE *fp;
1162 int len, i = 0;
1164 if ((fp = fopen(filename, "r")) == NULL) {
1165 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1166 norcfile = 1;
1167 return;
1169 norcfile = 0;
1170 while (fgets(temp, 128, fp)) {
1171 if (*temp != '\n') {
1172 if (menu) {
1173 ftune[i]=0;
1174 if(sscanf(temp, " %s %n(%ld) %n", name, &len, &ftune[i], &len)>=1) {
1175 char *pos;
1176 cname[i]=strdup(name);
1177 comment[i]=temp[len]?strdup(temp+len):"";
1178 /* Remove the end-of-line symbol */
1179 for (pos = comment[i]; *pos != '\0'; pos++) {
1180 if (*pos == '\n') {
1181 *pos = '\0';
1182 break;
1186 if(++i>=MAXCHAN)
1187 break;
1189 else if (strchr(temp, '[')) {
1190 menu = TRUE;
1194 tpst = i;
1195 fclose(fp);
1199 /* WriteRCFile function */
1200 void
1201 WriteRCFile(const char *filename, rckeys *keys)
1203 long i;
1204 FILE *fp;
1205 int key;
1207 if ((fp = fopen(filename, "w")) == NULL) {
1208 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1209 return;
1212 for (key=0; keys[key].label; key++)
1213 if (*keys[key].var)
1214 fprintf(fp, "%s = %s\n", keys[key].label, *keys[key].var);
1216 fprintf(fp, "\n[channel]\n");
1218 for (i = 0; i <= maxpst; i++)
1219 fprintf(fp, "%s (%ld)\t%s\n", cname[i], ftune[i], comment[i]);
1221 fclose(fp);
1225 /* InitPalette function */
1226 void
1227 InitPalette(void)
1229 if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
1230 perror ("ioctl VIDIOCGFBUF");
1231 exit(-1);
1233 if (vfb.base == NULL) {
1234 fprintf(stderr, "wmtv: no physical frame buffer access\n");
1235 exit(1);
1239 if (ioctl(tfd, VIDIOCGPICT, &vpic) < 0) {
1240 perror("ioctl VIDIOCGPICT");
1242 vpic.depth = vfb.depth;
1243 switch(vpic.depth) {
1244 case 8:
1245 vpic.palette = VIDEO_PALETTE_HI240;
1246 break;
1247 case 15:
1248 vpic.palette = VIDEO_PALETTE_RGB555;
1249 break;
1250 case 16:
1251 vpic.palette = VIDEO_PALETTE_RGB565;
1252 break;
1253 case 24:
1254 vpic.palette = VIDEO_PALETTE_RGB24;
1255 break;
1256 case 32:
1257 vpic.palette = VIDEO_PALETTE_RGB32;
1258 break;
1259 default:
1260 fprintf(stderr, "wmtv: unsupported depth %d\n", vpic.depth);
1261 exit(-1);
1263 if (ioctl(tfd, VIDIOCSPICT, &vpic) < 0) {
1264 perror("ioctl VIDIOCSPICT");
1267 /* InitConfig function */
1268 void
1269 InitConfig(void)
1271 int i;
1273 ParseRCFile(usrConfFile, wmtv_keys);
1274 ParseRCFile2(usrConfFile);
1276 if (norcfile) {
1277 ParseRCFile(sysConfFile, wmtv_keys);
1278 ParseRCFile2(sysConfFile);
1280 if (norcfile) {
1281 fprintf(stderr, "wmtv: error - config file not found\n");
1282 exit(1);
1286 if (maxpreset != NULL)
1287 maxpst = atoi(maxpreset) - 1;
1288 else
1289 maxpst = 1;
1291 if ((tpst) != atoi(maxpreset)) {
1292 fprintf(stderr, "wmtv: error - maxpreset value does not match total channel value\n");
1293 exit(1);
1295 if ((tfd = open(dev, O_RDWR)) < 0) {
1296 perror("open failed");
1298 card_present = TRUE;
1300 if (norm)
1301 for (i=0; i < CHAN_NAMES; i++) {
1302 if (!strcmp(chan_names[i].cname, norm)) {
1303 freqnorm = chan_names[i].cind;
1307 if (freqnorm == -1) {
1308 fprintf(stderr, "wmtv: error - set freqnorm in config file\n");
1309 exit(1);
1312 if (ioctl(tfd, VIDIOCGCAP, &vcap) < 0) {
1313 perror("ioctl VIDIOCGCAP");
1316 if (!(vcap.type & VID_TYPE_SCALES)) {
1317 fprintf(stderr, "%s: video device does not support scalling\n", progname);
1318 exit(1);
1320 if (!(vcap.type & VID_TYPE_CLIPPING)) {
1321 fprintf(stderr, "%s: video device does not support clipping\n", progname);
1324 if (fullscreen) {
1325 fswidth = atoi(strtok(fullscreen, "x\n"));
1326 fsheight = atoi(strtok(NULL, "x\n"));
1328 else {
1329 fswidth = 640;
1330 fsheight = 480;
1333 if (source) {
1334 for (i=0; i < vcap.channels; i++) {
1335 vchn.channel = i;
1336 if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0) {
1337 perror("ioctl VIDIOCGCHAN");
1339 if (!strcmp(vchn.name, source)) {
1340 if (vchn.tuners)
1341 cnotune = 0;
1342 else
1343 cnotune = 1;
1345 vsource = 1;
1346 tvsource = vchn.channel;
1348 if ((ioctl(tfd, VIDIOCSCHAN, &vchn)) < 0)
1349 perror("ioctl VIDIOCSCHAN");
1352 if (!vsource)
1353 fprintf(stderr, "wmtv: invalid source in config file\n");
1356 if (mode) {
1357 if (!cnotune) {
1358 vtun.tuner = 0;
1359 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
1360 perror("ioctl VIDIOCGTUNER");
1363 if (!strcmp(mode, "pal")) {
1364 if (vtun.flags & VIDEO_TUNER_PAL) {
1365 vtun.mode = VIDEO_MODE_PAL;
1366 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1367 perror("ioctl VIDIOCSTUNER");
1371 if (!strcmp(mode, "ntsc")) {
1372 if (vtun.flags & VIDEO_TUNER_NTSC) {
1373 vtun.mode = VIDEO_MODE_NTSC;
1374 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1375 perror("ioctl VIDIOCSTUNER");
1379 if (!strcmp(mode, "secam")) {
1380 if (vtun.flags & VIDEO_TUNER_SECAM) {
1381 vtun.mode = VIDEO_MODE_SECAM;
1382 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1383 perror("ioctl VIDIOCSTUNER");
1390 for (i=0; i < vcap.audios; i++) {
1391 vaud.audio = i;
1392 if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0) {
1393 perror("ioctl VIDIOCGAUDIO");
1395 if (!(vaud.flags & VIDEO_AUDIO_MUTE)) {
1396 vaud.flags |= VIDEO_AUDIO_MUTE;
1397 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) {
1398 perror("ioctl VIDIOCSAUDIO");
1403 if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
1404 perror("ioctl VIDIOCGFBUF");
1408 /* GetFrameBuffer function */
1409 void
1410 GetFrameBuffer(void)
1412 #if 0
1413 void *baseaddr = NULL;
1414 int evbr, erbr, flr = 0;
1415 int bankr, memr, depth;
1416 int i, n;
1417 int bytesperline, bitsperpixel;
1418 XPixmapFormatValues *pf;
1419 #endif
1421 if (!XGetWindowAttributes(display, DefaultRootWindow(display), &Winattr)) {
1422 fprintf(stderr, "wmtv: error getting winattr of root\n");
1425 #if 0
1426 depth = Winattr.depth;
1428 if (XF86DGAQueryExtension(display, &evbr, &erbr)) {
1429 XF86DGAQueryDirectVideo(display, XDefaultScreen(display), &flr);
1430 if (flr & XF86DGADirectPresent) {
1431 XF86DGAGetVideoLL(display, XDefaultScreen(display),
1432 (int *) &baseaddr, &bytesperline, &bankr, &memr);
1435 else {
1436 fprintf(stderr, "wmtv: error - XF86DGA Extensions not available\n");
1437 exit(1);
1441 pf = XListPixmapFormats(display, &n);
1442 for (i=0; i < n; i++) {
1443 if (pf[i].depth == depth) {
1444 depth = pf[i].bits_per_pixel;
1445 break;
1449 bitsperpixel = (depth+7) & 0xf8;
1450 bytesperline *= bitsperpixel/8;
1452 vfb.base = baseaddr;
1453 vfb.height = Winattr.height;
1454 vfb.width = Winattr.width;
1455 vfb.depth = bitsperpixel;
1456 vfb.bytesperline = bytesperline;
1458 if (Winattr.depth == 15)
1459 vfb.depth = 15;
1461 if (ioctl(tfd, VIDIOCSFBUF, &vfb) < 0) {
1462 perror("ioctl VIDIOCSFBUF");
1464 #endif
1468 /* DoFullScreen function */
1469 void
1470 DoFullScreen(void)
1472 int i;
1473 int evbr, erbr = 0;
1474 int rx, ry;
1475 unsigned long back_pix, fore_pix;
1476 unsigned int borderwidth = 0;
1478 Window junkwin;
1479 XSizeHints fmsizehints;
1480 XWMHints fmxwmhints;
1481 XGCValues gcv;
1482 unsigned long gcm;
1483 unsigned long valuemask;
1485 XSetWindowAttributes fmWinattr;
1486 XWindowAttributes fmwinattr;
1489 ccapt = 0;
1490 if (ioctl (tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1491 perror("ioctl VIDIOCCAPTURE");
1494 fmsizehints.x = 0;
1495 fmsizehints.y = 0;
1496 fmsizehints.width = fswidth;
1497 fmsizehints.height = fsheight;
1498 fmsizehints.max_width = vcap.maxwidth;
1499 fmsizehints.max_height = vcap.maxheight;
1500 fmsizehints.min_width = fswidth;
1501 fmsizehints.min_height = fsheight;
1502 fmsizehints.flags = (USPosition | USSize | PSize | PMinSize | PMaxSize);
1504 valuemask = 0;
1506 back_pix = WhitePixel(display, DefaultScreen(display));
1507 fore_pix = BlackPixel(display, DefaultScreen(display));
1509 fmwin = XCreateWindow(display, DefaultRootWindow(display), fmsizehints.x,
1510 fmsizehints.y, fmsizehints.width, fmsizehints.height,
1511 borderwidth, CopyFromParent, InputOutput,
1512 CopyFromParent, valuemask, &fmWinattr);
1515 XSetWMNormalHints(display, fmwin, &fmsizehints);
1517 gcm = (GCForeground | GCBackground | GCGraphicsExposures);
1518 gcv.foreground = fore_pix;
1519 gcv.background = back_pix;
1520 gcv.graphics_exposures = 0;
1522 fmGC = XCreateGC(display, DefaultRootWindow(display), gcm, &gcv);
1524 XSelectInput(display, fmwin, ButtonPressMask | ExposureMask |
1525 ButtonReleaseMask | PointerMotionMask |
1526 StructureNotifyMask | VisibilityChangeMask | KeyPressMask );
1528 fmxwmhints.flags = StateHint;
1529 fmxwmhints.initial_state = NormalState;
1531 XSetWMHints(display, fmwin, &fmxwmhints);
1534 if (XF86VidModeQueryExtension(display, &evbr, &erbr)) {
1535 vidmode = TRUE;
1537 else {
1538 fprintf(stderr, "wmtv: xf86mode extension not present\n");
1539 fprintf(stderr, " switch disabled\n");
1543 XMapWindow(display, fmwin);
1545 usleep(50000L);
1546 if (!XGetWindowAttributes(display, fmwin, &fmwinattr)) {
1547 fprintf(stderr, "wmtv: error getting winattr of fmwin\n");
1550 usleep(50000L);
1551 if (!XTranslateCoordinates(display, fmwin, DefaultRootWindow(display),
1552 -fmwinattr.border_width,
1553 -fmwinattr.border_width,
1554 &rx, &ry, &junkwin)) {
1555 fprintf(stderr, "wmtv: error translating coordinates for fmwin");
1558 vswin.width = fswidth;
1559 vswin.height = fsheight;
1560 vswin.x = fmsizehints.x + rx;
1561 vswin.y = fmsizehints.y + ry;
1562 vswin.clipcount = 0;
1564 if (ioctl(tfd, VIDIOCSWIN, &vswin) < 0) {
1565 perror("ioctl VIDIOCSWIN");
1568 ccapt = 1;
1569 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1570 perror("ioctl VIDIOCCAPTURE");
1572 fmode = TRUE;
1574 if (vidmode) {
1575 XF86VidModeGetModeLine(display, XDefaultScreen(display), &dcret, &scmode);
1576 XF86VidModeGetAllModeLines(display, XDefaultScreen(display), &tml, &modelines);
1578 for (i=0; i < tml; i++) {
1579 if ((modelines[i]->hdisplay == fswidth) &&
1580 (modelines[i]->vdisplay == fsheight)) {
1581 fullscreenmode = modelines[i];
1582 mode_present = TRUE;
1583 break;
1587 if (!mode_present) {
1588 fprintf(stderr, "wmtv: mode line for resolution %d x %d not found\n", vcap.maxwidth, vcap.maxheight);
1591 XRaiseWindow(display, fmwin);
1592 if (mode_present) {
1594 XF86VidModeSwitchToMode(display, XDefaultScreen(display), fullscreenmode);
1595 XF86VidModeSetViewPort(display, XDefaultScreen(display), vswin.x, vswin.y);
1596 XGrabPointer(display, fmwin, True, 0, GrabModeAsync, GrabModeAsync,
1597 fmwin, None, CurrentTime);
1603 /* RetScreen function */
1604 void
1605 RetScreen()
1607 int i;
1608 XF86VidModeModeInfo *scm = NULL;
1610 ccapt = 0;
1611 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt)) {
1612 perror("ioctl VIDIOCCAPTURE");
1615 if (mode_present) {
1616 for (i = 0; i < tml; i++) {
1617 if ((modelines[i]->hdisplay == Winattr.width) &&
1618 (modelines[i]->vdisplay==Winattr.height))
1619 scm = modelines[i];
1622 scm->dotclock = dcret;
1623 scm->hdisplay = scmode.hdisplay;
1624 scm->hsyncstart = scmode.hsyncstart;
1625 scm->hsyncend = scmode.hsyncend;
1626 scm->htotal = scmode.htotal;
1627 scm->vdisplay = scmode.vdisplay;
1628 scm->vsyncstart = scmode.vsyncstart;
1629 scm->vsyncend = scmode.vsyncend;
1630 scm->vtotal = scmode.vtotal;
1631 scm->flags = scmode.flags;
1633 scm->privsize = scmode.privsize;
1634 scm->private = scmode.private;
1637 XClearWindow(display, fmwin);
1638 XFreeGC(display, fmGC);
1639 XMapRaised(display, fmwin);
1640 XUnmapWindow(display, fmwin);
1641 XUngrabPointer(display, CurrentTime);
1643 else {
1644 XClearWindow(display, fmwin);
1645 XFreeGC(display, fmGC);
1646 XMapRaised(display, fmwin);
1647 XUnmapWindow(display, fmwin);
1650 if (vidmode && mode_present) {
1651 XF86VidModeSwitchToMode(display, XDefaultScreen(display), scm);
1652 vidmode = FALSE;
1654 fmode = FALSE;
1655 mode_present = FALSE;
1657 ccapt = 1;
1658 if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0) {
1659 perror("ioctl VIDIOCSWIN");
1662 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1663 perror("ioctl VIDIOCCAPTURE");
1665 RedrawWindow();
1668 /* GrabImage function */
1669 void
1670 GrabImage(void)
1674 /* Usage function */
1675 void
1676 Usage(void)
1678 fprintf(stderr, "\n");
1679 fprintf(stderr, "wmtv v%s, Copyright (c) 1999 Wee Liang <wliang@tartarus.uwa.edu.au>\n", VERSION);
1680 fprintf(stderr, "usage: wmtv [%s]\n", OPTIONS);
1681 fprintf(stderr, " -c, --device <file>\tsets video4linux device to use\n");
1682 fprintf(stderr, " -d, --display <host:vs>\tsets display name\n");
1683 fprintf(stderr, " -g, --geometry <{+-}XP{+-}YP>\tsets geometry\n");
1684 fprintf(stderr, " -b, --bpp\t\t\tdisplay color depth\n");
1685 fprintf(stderr, " -e, --exe <filename>\t\tprogram to execute\n");
1686 fprintf(stderr, " -v, --version\t\t\tprints version information\n");
1687 fprintf(stderr, " -h, --help\t\t\tprints this message\n");
1688 fprintf(stderr, "\n");
1692 /* Version function */
1693 void
1694 Version(void)
1696 fprintf(stderr, "wmtv version %s\n", VERSION);