wmtv: Fix typo
[dockapps.git] / wmtv / src / wmtv.c
blobc1c9b09bc74ad6c51ce40ba2b5a6077a5ad5a262
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/XKBlib.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 Display *display;
89 int tfd;
90 int card_present = FALSE;
91 int ntfb_status = SETOFF;
92 char *maxpreset = NULL;
93 char **chan = NULL;
94 int mode_present = FALSE;
96 int chn = 0;
97 int aud = 0;
98 int tpst = 0;
99 int cchannel = 0;
100 int timebutton = 0;
101 int tvsource = 0;
102 int ccapt;
103 int norcfile = 0;
104 int ic = 0;
105 int cnotune = 0;
106 int vsource = 0;
107 int isource = 0;
108 int compchannel = 0;
109 int vidmode = 0;
110 int fmode = 0;
111 int mute = 0;
112 int dcret;
113 int tml;
114 int fswidth = 0;
115 int fsheight = 0;
116 pid_t child_pid = -1;
117 int restart = FALSE;
119 unsigned long ccrfreq;
120 unsigned long rfreq;
121 unsigned long st;
123 char *norm = NULL;
124 char *source;
125 char *mode = NULL;
126 char *fullscreen = NULL;
127 int freqnorm = -1;
128 char *cname[MAXCHAN];
129 char *comment[MAXCHAN];
130 long ftune[MAXCHAN];
131 char *progname;
132 char *dev = "/dev/video";
134 char *sysConfFile = GLOBALCONFFILE;
135 char *usrConfFile;
137 int wmtv_mask_width = 64;
138 int wmtv_mask_height = 64;
139 char wmtv_mask_bits[64*64];
141 int btime = 0;
142 int but_pressed = FALSE;
143 int but_clicked = FALSE;
144 int maxpst;
145 int x_lc;
146 int y_lc;
147 Time t_lc;
149 rckeys wmtv_keys[] = {
150 { "freqnorm", &norm },
151 { "source", &source },
152 { "maxpreset", &maxpreset },
153 { "mode", &mode },
154 { "fullscreen", &fullscreen },
155 { NULL, NULL }
158 XEvent Event;
159 XWindowAttributes Winattr;
160 Window fmwin;
161 GC fmGC;
162 XF86VidModeModeInfo **modelines, *fullscreenmode = NULL;
163 XF86VidModeModeLine scmode;
165 struct video_capability vcap;
166 struct video_buffer vfb;
167 struct video_window vwin;
168 struct video_window vswin;
169 struct video_channel vchn, vchns;
170 struct video_picture vpic;
171 struct video_tuner vtun;
172 struct video_audio vaud;
173 struct video_mbuf vmbuf;
174 struct video_mmap vmmap;
175 struct video_clip vclip[2];
176 struct video_clip vclip2[2];
179 /* Function prototypes */
180 void TVOn(void);
181 void TVOff(void);
182 void TuneTV(void);
183 void ChanUp(void);
184 void ChanDown(void);
185 void FineTuneUp(void);
186 void FineTuneDown(void);
187 void ScanUp(void);
188 void ScanDown(void);
190 void ButtonUp(int);
191 void ButtonDown(int);
192 void Capture(void);
193 void MuteAudio(void);
194 void UnMuteAudio(void);
195 void VolumeUp(void);
196 void VolumeDown(void);
197 void DrawPresetChan(int);
198 void DoFullScreen(void);
199 void GetFrameBuffer(void);
200 void RetScreen(void);
201 void GrabImage(void);
203 void ParseRCFile(const char *, rckeys *);
204 void ParseRCFile2(const char *);
205 void WriteRCFile(const char *, rckeys *);
206 void InitConfig(void);
207 void InitPalette(void);
209 void Usage(void);
210 void Version(void);
212 void
213 sigchld_handler(int i)
215 pid_t pid;
216 pid = waitpid((pid_t)-1, NULL, WNOHANG);
217 while (pid>(pid_t)0) {
218 if (pid == child_pid) {
219 child_pid = -1;
220 restart = TRUE;
222 pid = waitpid((pid_t)-1, NULL, WNOHANG);
226 void
227 init_signal()
229 struct sigaction sa;
231 sa.sa_handler = &sigchld_handler;
232 sigemptyset(&sa.sa_mask);
233 sa.sa_flags = SA_RESTART;
234 sigaction(SIGCHLD, &sa, NULL);
237 char *
238 expand_format(char *format, char *letters, char **expansions)
240 char *string;
241 unsigned int string_pos = 0;
242 unsigned int size;
243 size = strlen(format)+1;
244 string = (char *)malloc(size*sizeof(char));
245 for (; *format != '\0'; format++) {
246 if (*format == '%') {
247 format++;
248 if (*format != '%') {
249 unsigned int i;
250 for (i = 0; letters[i] != '\0'; i++) {
251 if (letters[i] == *format)
252 break;
254 if (letters[i] != '\0') {
255 unsigned int expansion_size;
256 expansion_size = strlen(expansions[i]);
257 while (string_pos+expansion_size+1 > size) {
258 size *= 2;
259 string = realloc(string, size*sizeof(char));
261 memcpy(string+string_pos, expansions[i], expansion_size);
262 string_pos += expansion_size;
263 continue;
265 else {
266 format--;
270 while (string_pos+1+1 > size) {
271 size *= 2;
272 string = realloc(string, size*sizeof(char));
274 string[string_pos] = *format;
275 string_pos++;
277 string[string_pos] = '\0';
278 return string;
281 /* main function */
283 main(int argc, char *argv[])
285 int c, opind;
286 int pressed_button = -1;
287 /* pid_t pid; */
288 static struct option long_options[] = {
289 {"device", 1, 0, 'c'},
290 {"display", 1, 0, 'd'},
291 {"geometry", 1, 0, 'g'},
292 {"bpp", 1, 0, 'b'},
293 {"exe", 1, 0, 'e'},
294 {"help", 0, 0, 'h'},
295 {"version", 0, 0, 'v'},
296 {0, 0, 0, 0}
299 progname = strdup(argv[0]);
302 char *home = getenv("HOME");
304 if (home == NULL) {
305 fprintf(stderr, "wmtv: $HOME should be set.\n");
306 exit(1);
309 usrConfFile = (char *)malloc(sizeof(char)*(strlen(home)+8+1));
310 strcpy(usrConfFile, home);
311 strcat(usrConfFile, "/.wmtvrc");
314 while (1) {
315 opind = 0;
316 c = getopt_long (argc, argv, OPTIONS, long_options, &opind);
317 if (c == -1)
318 break;
320 switch(c)
322 case 0:
324 fprintf(stderr, "wmtv: option - %s", long_options[opind].name);
325 if (optarg)
326 fprintf(stderr, " with arg %s", optarg);
327 printf("\n");
329 break;
330 case 'd':
331 display_name = strdup(optarg);
332 break;
333 case 'g':
334 geometry = strdup(optarg);
335 break;
336 case 'e':
337 exe = strdup(optarg);
338 /* strcat(exe, " &"); */
339 break;
340 case 'c':
341 dev = strdup(optarg);
342 break;
343 case 'b':
344 fprintf(stderr, "wmtv: option not implemented yet\n");
345 Usage();
346 exit(1);
347 break;
348 case 'v':
349 Version();
350 exit(0);
351 break;
352 default:
353 Usage();
354 exit(1);
358 /* creat windows */
359 createXBMfromXPM (wmtv_mask_bits, wmtv_master_xpm,
360 wmtv_mask_width, wmtv_mask_height);
361 openXwindow (argc, argv, wmtv_master_xpm, wmtv_mask_bits,
362 wmtv_mask_width, wmtv_mask_height);
364 AddMouseRegion (NTFB, 47, 48, 59, 59); /* On/SetTune/Off Button */
365 AddMouseRegion (SCANLB, 23, 48, 35, 59); /* Left Preset/Scan Button */
366 AddMouseRegion (SCANRB, 35, 48, 47, 59); /* Right Preset/Scan Button */
367 AddMouseRegion (FULLSB, 5, 5, 59, 44); /* Toggle FullScreen */
369 init_signal();
371 /* wmtv main loop */
372 while (1)
374 if (restart) {
375 TVOn();
376 if (ntfb_status == SETOFF) {
377 ntfb_status = SETON;
378 RedrawWindow();
379 XFlush(display);
381 restart = FALSE;
382 continue;
384 while (XPending(display))
386 XNextEvent(display, &Event);
387 switch (Event.type) {
388 case Expose:
389 RedrawWindow();
390 break;
391 case DestroyNotify:
392 XCloseDisplay(display);
393 ccapt = 0;
394 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
395 perror("ioctl VIDIOCCAPTURE");
397 close(tfd);
398 usleep(50000L);
399 exit(0);
400 break;
401 case ButtonPress:
402 if ((Event.xany.window == fmwin) && fmode) {
403 RetScreen();
405 else {
406 pressed_button = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
407 switch (pressed_button) {
408 case NTFB:
409 ButtonDown(NTFB);
410 t_lc = Event.xbutton.time;
411 but_pressed = TRUE;
412 break;
413 case SCANLB:
414 ButtonDown(SCANLB);
415 if (ntfb_status == SETUNE) {
416 switch (Event.xbutton.button) {
417 case 1:
418 timebutton = 1;
419 while (timebutton == 1)
420 if (isource == TELEVISION)
421 ScanDown();
422 break;
423 case 3:
424 if (isource == TELEVISION)
425 FineTuneDown();
426 break;
429 else if (ntfb_status == SETON)
430 ChanDown();
431 break;
432 case SCANRB:
433 ButtonDown(SCANRB);
434 if (ntfb_status == SETUNE) {
435 switch (Event.xbutton.button) {
436 case 1:
437 timebutton = 1;
438 while (timebutton)
439 if (isource == TELEVISION)
440 ScanUp();
441 break;
442 case 3:
443 if (isource == TELEVISION)
444 FineTuneUp();
445 break;
448 else if (ntfb_status == SETON)
449 ChanUp();
450 break;
451 case FULLSB:
452 ButtonDown(FULLSB);
453 switch (Event.xbutton.button) {
454 case 1:
455 but_pressed = TRUE;
456 break;
457 case 2:
458 but_pressed = TRUE;
459 break;
460 case 3:
461 if (!mute) {
462 MuteAudio();
464 else {
465 UnMuteAudio();
467 break;
469 break;
471 RedrawWindow();
473 break;
474 case ButtonRelease:
475 switch (pressed_button) {
476 case NTFB:
477 ButtonUp(NTFB);
478 if (but_pressed) {
479 if (Event.xbutton.time - t_lc >= 900) {
480 btime = TRUE;
481 but_pressed = FALSE;
485 if (ntfb_status == SETOFF) {
486 if (child_pid == -1) {
487 ntfb_status = SETON;
488 TVOn();
491 else if (ntfb_status == SETON) {
492 if (!btime) {
493 ntfb_status = SETUNE;
494 copyXPMArea(96, 79, 11, 7, 6, 50);
495 RedrawWindowXYWH(6, 50, 11, 7);
497 else if (btime) {
498 ntfb_status = SETOFF;
499 btime = FALSE;
500 ic = TRUE;
501 TVOff();
504 else if (ntfb_status == SETUNE) {
505 if (!btime) {
506 ftune[cchannel] = (rfreq - ccrfreq);
507 /* fprintf(stderr, "wmtv: finetune offset = %ld\n", ftune[cchannel]); */
508 WriteRCFile(usrConfFile, wmtv_keys);
509 ntfb_status = SETON;
510 DrawPresetChan(cchannel);
512 else if (btime) {
513 ntfb_status = SETOFF;
514 btime = FALSE;
515 ic = TRUE;
516 TVOff();
519 break;
520 case SCANLB:
521 ButtonUp(SCANLB);
522 if (ntfb_status == SETUNE)
523 timebutton = 0;
524 break;
525 case SCANRB:
526 ButtonUp(SCANRB);
527 if (ntfb_status == SETUNE)
528 timebutton = 0;
529 break;
530 case FULLSB:
531 ButtonUp(FULLSB);
532 switch (Event.xbutton.button) {
533 case 1: {
534 if (but_clicked) {
535 but_pressed = FALSE;
536 but_clicked = FALSE;
538 if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
540 if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
541 if (exe) {
542 pid_t pid;
543 char *command;
544 char *letters = "#nf";
545 char *(expansions[3]);
546 ntfb_status = SETOFF;
547 TVOff();
548 expansions[0] = malloc(3*sizeof(char));
549 snprintf(expansions[0], 3, "%d", cchannel+1);
550 expansions[1] = comment[cchannel];
551 expansions[2] = malloc(15*sizeof(char));
552 snprintf(expansions[2], 15, "%.3f", (double)rfreq/(double)st);
553 command = expand_format(exe, letters, expansions);
554 /* system(exe); */
555 child_pid = fork();
556 if (child_pid == (pid_t) 0) {
557 char *argv[4];
558 argv[0] = "sh";
559 argv[1] = "-c";
560 argv[2] = command;
561 argv[3] = NULL;
562 execv("/bin/sh", argv);
563 exit(-1);
565 free(expansions[0]);
566 free(expansions[2]);
567 free(command);
568 pid = waitpid(child_pid, NULL, WNOHANG);
569 if (pid != 0) {
570 child_pid = -1;
571 restart = TRUE;
573 /* printf("Returned pid:\n"); */
575 #if 0
576 pid = fork();
578 /* child */
579 if (pid == (pid_t) 0) {
580 execlp("xawtv", "xawtv", "&", (char *) 0);
583 else if (pid < (pid_t) 0) {
584 perror("fork");
587 /* parent */
588 else {
589 if (waitpid(pid, NULL, 0) < 0) {
590 perror("waitpid");
591 #endif
593 else {
594 DoFullScreen();
600 if (but_pressed) {
601 t_lc = Event.xbutton.time;
602 x_lc = Event.xbutton.x;
603 y_lc = Event.xbutton.y;
604 but_clicked = TRUE;
605 but_pressed = FALSE;
608 break;
609 case 2: {
610 if (but_clicked) {
611 but_pressed = FALSE;
612 but_clicked = FALSE;
614 if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
616 if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
617 DoFullScreen();
622 if (but_pressed) {
623 t_lc = Event.xbutton.time;
624 x_lc = Event.xbutton.x;
625 y_lc = Event.xbutton.y;
626 but_clicked = TRUE;
627 but_pressed = FALSE;
630 break;
631 case 3:
632 break;
634 break;
636 RedrawWindow();
637 break;
638 case VisibilityNotify:
639 switch(Event.xvisibility.state) {
640 case VisibilityFullyObscured:
641 ccapt = 0;
642 if (tfd && (ntfb_status != SETOFF) && !fmode) {
643 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
644 perror("ioctl VIDIOCCAPTURE");
647 break;
648 case VisibilityPartiallyObscured:
649 ccapt = 0;
650 if (tfd && (ntfb_status != SETOFF) && !fmode) {
651 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
652 perror("ioctl VIDIOCCAPTURE");
655 break;
656 case VisibilityUnobscured:
657 ccapt = 1;
658 if (tfd && (ntfb_status != SETOFF) && !fmode) {
659 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
660 perror("ioctl VIDIOCCAPTURE");
663 break;
665 RedrawWindow();
666 break;
667 case KeyPress:
668 if ((Event.xany.window == fmwin) && fmode) {
669 switch(XkbKeycodeToKeysym(display, Event.xkey.keycode, 0, 0)) {
670 case XK_Up:
671 if (isource == TELEVISION)
672 ChanUp();
673 break;
674 case XK_Down:
675 if (isource == TELEVISION)
676 ChanDown();
677 break;
678 case XK_Right:
679 VolumeUp();
680 break;
681 case XK_Left:
682 VolumeDown();
683 break;
684 case XK_m:
685 if (!mute) {
686 MuteAudio();
688 else {
689 UnMuteAudio();
691 break;
692 case XK_Escape:
693 RetScreen();
694 break;
695 default:
696 break;
699 default:
700 break;
702 XFlush(display);
704 usleep(50000L);
706 return(0);
710 /* ButtonDown function */
711 void
712 ButtonDown(int button)
714 switch (button) {
715 case NTFB:
716 copyXPMArea(79, 100, 12, 11, 47, 48);
717 RedrawWindowXYWH (47, 48, 12, 11);
718 break;
719 case SCANLB:
720 copyXPMArea(55, 100, 12, 11, 23, 48);
721 RedrawWindowXYWH(35, 48, 12, 11);
722 break;
723 case SCANRB:
724 copyXPMArea(67, 100, 12, 11, 35, 48);
725 RedrawWindowXYWH(35, 48, 12, 11);
726 break;
727 case FULLSB:
728 break;
733 /* ButtonUp function */
734 void
735 ButtonUp(int button)
737 switch (button) {
738 case NTFB:
739 copyXPMArea(79, 88, 12, 11, 47, 48);
740 RedrawWindowXYWH(47, 48, 12, 11);
741 break;
742 case SCANLB:
743 copyXPMArea(55, 88, 12, 11, 23, 48);
744 RedrawWindowXYWH(23, 48, 12, 11);
745 break;
746 case SCANRB:
747 copyXPMArea(67, 88, 12, 11, 35, 48);
748 RedrawWindowXYWH(35, 48, 12, 11);
749 break;
750 case FULLSB:
751 break;
756 /* TVOn function */
757 void
758 TVOn(void)
760 int i;
761 Window junkwin;
762 int rx, ry;
763 char *p;
765 XWindowAttributes winattr;
767 if (!XGetWindowAttributes (display, iconwin, &winattr)) {
768 fprintf(stderr, "wmtv: error getting winattr of iconwin\n");
771 if (!XTranslateCoordinates(display, iconwin, winattr.root,
772 -winattr.border_width,
773 -winattr.border_width,
774 &rx, &ry, &junkwin)) {
775 fprintf(stderr, "wmtv: error translating coordinates\n");
778 /* This part was taken from xawtv's source code */
779 switch (system("v4l-conf -q")) {
780 case -1: /* can't run */
781 fprintf(stderr,"couldn't start v4l-conf\n");
782 break;
783 case 0: /* ok */
784 break;
785 default: /* non-zero return */
786 fprintf(stderr,"v4l-conf had some trouble, "
787 "trying to continue anyway\n");
789 /* End of "stolen" part */
790 InitConfig();
791 GetFrameBuffer();
792 InitPalette();
794 ccapt = 1;
796 vwin.x = rx;
797 vwin.y = ry + 5;
799 vwin.width = 64;
800 vwin.height = 39;
802 vclip[0].x = 0; /* Clipping Rect 1 */
803 vclip[0].y = 0;
804 vclip[0].width = 5;
805 vclip[0].height = 39;
806 vclip[1].x = 59; /* Clipping Rect 2 */
807 vclip[1].y = 0;
808 vclip[1].width = 5;
809 vclip[1].height = 39;
811 vwin.clips = vclip;
812 vwin.clipcount = 2;
814 vchn.channel = tvsource;
815 vaud.audio = tvsource;
817 if (source) {
818 p = source;
819 if (*p == 'T')
820 isource = TELEVISION;
821 else if (*p == 'C') {
822 isource = COMPOSITE;
823 while (isalpha(*p))
824 ++p;
825 compchannel = atoi(p);
827 else if (*p == 'S')
828 isource = SVIDEO;
831 if (!cnotune) {
832 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0)
833 perror("ioctl VIDIOCGTUNER");
834 if (vtun.flags & VIDEO_TUNER_LOW)
835 st = 16000;
836 else
837 st = 16;
840 if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0)
841 perror("ioctl VIDIOCGCHAN");
843 if (vchn.flags & VIDEO_VC_AUDIO) {
844 if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0)
845 perror("ioctl VIDIOCGAUDIO");
848 if (vaud.flags & VIDEO_AUDIO_MUTE) {
849 vaud.flags &= ~VIDEO_AUDIO_MUTE; /* Unmute */
850 vaud.volume = 0xFFFF;
853 if (isource == TELEVISION) {
854 for (i=0; i < CHAN_ENTRIES; i++) {
855 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
856 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
857 ccrfreq = rfreq - ftune[cchannel];
858 break;
861 DrawPresetChan(cchannel);
863 else if (isource == COMPOSITE) {
864 DrawPresetChan(compchannel);
866 else if (isource == SVIDEO) {
867 DrawPresetChan(-1);
870 if (vchn.flags & VIDEO_VC_AUDIO) {
871 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
872 perror("ioctl VIDIOCSAUDIO");
876 if (ioctl(tfd, VIDIOCSCHAN, &vchn) < 0)
877 perror("ioctl VIDIOCSCHAN");
879 if (!cnotune) {
880 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
881 perror("ioctl VIDIOCSFREQ");
884 if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0)
885 perror("ioctl VIDIOCSWIN");
887 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
888 perror("ioctl VIDIOCCAPTURE");
892 /* TVOff function */
893 void
894 TVOff(void)
896 ccapt = 0;
898 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
899 perror("ioctl VIDIOCCAPTURE");
901 vaud.audio = tvsource;
902 vaud.volume = 0;
903 vaud.flags |= VIDEO_AUDIO_MUTE;
905 if (vchn.flags & VIDEO_VC_AUDIO) {
906 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
907 perror("ioctl VIDIOCSAUDIO");
910 close(tfd);
911 copyXPMArea(66, 79, 11, 7, 6, 50);
912 RedrawWindowXYWH(6, 50, 11, 7);
916 /* VolumeUp function */
917 void
918 VolumeUp(void)
920 if(vchn.flags & VIDEO_VC_AUDIO) {
921 if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
922 fprintf(stderr, "Warning: v4l device does not support volume control.\n");
923 else if (vaud.volume <= 0xEEEE) {
924 vaud.audio = tvsource;
925 vaud.volume += 0x1111;
926 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
927 perror("ioctl VIDIOCSAUDIO");
933 /* VoumeDown function */
934 void
935 VolumeDown(void)
937 if (vchn.flags & VIDEO_VC_AUDIO) {
938 if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
939 fprintf(stderr, "Warning: v4l device does not support volume control.\n");
940 else if (vaud.volume >= 0x1111) {
941 vaud.audio = tvsource;
942 vaud.volume -= 0x1111;
943 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
944 perror("ioctl VIDIOCSAUDIO");
949 /* MuteAudio function */
950 void
951 MuteAudio(void)
953 if (vchn.flags & VIDEO_VC_AUDIO) {
954 vaud.audio = tvsource;
955 /* vaud.volume = 0; */
956 vaud.flags |= VIDEO_AUDIO_MUTE;
957 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
958 perror("ioctl VIDIOCSAUDIO");
960 mute = TRUE;
964 /* UnMuteAudio function */
965 void
966 UnMuteAudio(void)
968 if ((vchn.flags & VIDEO_VC_AUDIO) && (vaud.flags & VIDEO_AUDIO_MUTE)) {
969 vaud.audio = tvsource;
970 /* vaud.volume = (0xFFFF/2)+1; */
971 vaud.flags &= ~VIDEO_AUDIO_MUTE;
972 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
973 perror("ioctl VIDIOCSAUDIO");
975 mute = FALSE;
979 /* ScanUp function */
980 void
981 ScanUp(void)
983 rfreq += 2;
984 usleep(50000L);
985 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
986 perror("ioctl VIDIOCSFREQ");
988 usleep(10000L);
989 vtun.tuner = 0;
990 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
991 perror("ioctl VIDIOCGTUNER");
993 if (vtun.signal == 0xFFFF) {
994 timebutton = 0;
1000 /* ScanDown function */
1001 void
1002 ScanDown(void)
1004 rfreq -= 2;
1005 usleep(50000L);
1006 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
1007 perror("ioctl VIDIOCSFREQ");
1009 usleep(10000L);
1010 vtun.tuner = 0;
1011 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
1012 perror("ioctl VIDIOCGTUNER");
1014 if (vtun.signal == 0xFFFF) {
1015 timebutton = 0;
1020 /* FineTuneUp function */
1021 void
1022 FineTuneUp(void)
1024 rfreq += 1;
1025 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
1026 perror("ioctl VIDIOCSFREQ");
1031 /* FineTuneDown function */
1032 void
1033 FineTuneDown(void)
1035 rfreq -= 1;
1036 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
1037 perror("ioctl VIDIOCSFREQ");
1042 /* ChanUp function */
1043 void
1044 ChanUp(void)
1046 int i;
1047 if (cchannel < maxpst)
1048 ++cchannel;
1049 for (i=0; i < CHAN_ENTRIES; i++) {
1050 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
1051 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
1052 ccrfreq = rfreq - ftune[cchannel];
1053 break;
1057 DrawPresetChan(cchannel);
1058 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
1059 perror("ioctl VIDIOCSFREQ");
1063 /* ChanDown function */
1064 void
1065 ChanDown(void)
1067 int i;
1068 if (cchannel != 0)
1069 --cchannel;
1070 for (i=0; i < CHAN_ENTRIES; i++) {
1071 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
1072 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
1073 ccrfreq = rfreq - ftune[cchannel];
1074 break;
1078 DrawPresetChan(cchannel);
1079 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
1080 perror("ioctl VIDIOCSFREQ");
1084 /* DrawPresetChan function */
1085 void
1086 DrawPresetChan(int cchannel)
1088 char temp[10];
1089 char *p = temp;
1090 int j=0;
1091 int k=6;
1093 if (isource == TELEVISION) {
1094 sprintf(temp, "%02d", cchannel+1);
1096 if (*p == '0') {
1097 copyXPMArea(66, 79, 5, 7, k, 50);
1098 k += 6;
1099 j++;
1100 p++;
1102 while (j < 2) {
1103 copyXPMArea((*p-'0')*6 + 1, 79, 5, 7, k, 50);
1104 k += 6;
1105 p++;
1106 j++;
1110 else if (isource == COMPOSITE) {
1111 copyXPMArea (109, 79, 5, 7, 6, 50);
1112 copyXPMArea ((compchannel*6) + 1, 79, 5, 7, 12, 50);
1115 else if (isource == SVIDEO) {
1116 copyXPMArea(116, 79, 11, 7, 6, 50);
1119 RedrawWindowXYWH(6, 50, 11, 7);
1123 /* ParseRCFile function */
1124 void
1125 ParseRCFile(const char *filename, rckeys *keys)
1127 char *p;
1128 char temp[128];
1129 char *tokens = " =\t\n";
1130 FILE *fp;
1131 int key = 0;
1133 if ((fp = fopen(filename, "r")) == NULL) {
1134 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1135 norcfile = 1;
1136 return;
1138 norcfile = 0;
1139 while (fgets(temp, 128, fp)) {
1140 if (temp[0] != '\n') {
1141 p = strtok(temp, tokens);
1142 for (key=0; keys[key].label; key++) {
1143 if ((!strcmp(p, keys[key].label))) {
1144 p = strtok(NULL, tokens);
1145 free(*keys[key].var);
1146 *keys[key].var = strdup(p);
1147 break;
1152 fclose(fp);
1156 /* ParseRCFile2 function */
1157 void
1158 ParseRCFile2(const char *filename)
1160 int menu = FALSE;
1161 char temp[128], name[128];
1162 FILE *fp;
1163 int len, i = 0;
1165 if ((fp = fopen(filename, "r")) == NULL) {
1166 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1167 norcfile = 1;
1168 return;
1170 norcfile = 0;
1171 while (fgets(temp, 128, fp)) {
1172 if (*temp != '\n') {
1173 if (menu) {
1174 ftune[i]=0;
1175 if(sscanf(temp, " %s %n(%ld) %n", name, &len, &ftune[i], &len)>=1) {
1176 char *pos;
1177 cname[i]=strdup(name);
1178 comment[i]=temp[len]?strdup(temp+len):"";
1179 /* Remove the end-of-line symbol */
1180 for (pos = comment[i]; *pos != '\0'; pos++) {
1181 if (*pos == '\n') {
1182 *pos = '\0';
1183 break;
1187 if(++i>=MAXCHAN)
1188 break;
1190 else if (strchr(temp, '[')) {
1191 menu = TRUE;
1195 tpst = i;
1196 fclose(fp);
1200 /* WriteRCFile function */
1201 void
1202 WriteRCFile(const char *filename, rckeys *keys)
1204 long i;
1205 FILE *fp;
1206 int key;
1208 if ((fp = fopen(filename, "w")) == NULL) {
1209 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1210 return;
1213 for (key=0; keys[key].label; key++)
1214 if (*keys[key].var)
1215 fprintf(fp, "%s = %s\n", keys[key].label, *keys[key].var);
1217 fprintf(fp, "\n[channel]\n");
1219 for (i = 0; i <= maxpst; i++)
1220 fprintf(fp, "%s (%ld)\t%s\n", cname[i], ftune[i], comment[i]);
1222 fclose(fp);
1226 /* InitPalette function */
1227 void
1228 InitPalette(void)
1230 if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
1231 perror ("ioctl VIDIOCGFBUF");
1232 exit(-1);
1234 if (vfb.base == NULL) {
1235 fprintf(stderr, "wmtv: no physical frame buffer access\n");
1236 exit(1);
1240 if (ioctl(tfd, VIDIOCGPICT, &vpic) < 0) {
1241 perror("ioctl VIDIOCGPICT");
1243 vpic.depth = vfb.depth;
1244 switch(vpic.depth) {
1245 case 8:
1246 vpic.palette = VIDEO_PALETTE_HI240;
1247 break;
1248 case 15:
1249 vpic.palette = VIDEO_PALETTE_RGB555;
1250 break;
1251 case 16:
1252 vpic.palette = VIDEO_PALETTE_RGB565;
1253 break;
1254 case 24:
1255 vpic.palette = VIDEO_PALETTE_RGB24;
1256 break;
1257 case 32:
1258 vpic.palette = VIDEO_PALETTE_RGB32;
1259 break;
1260 default:
1261 fprintf(stderr, "wmtv: unsupported depth %d\n", vpic.depth);
1262 exit(-1);
1264 if (ioctl(tfd, VIDIOCSPICT, &vpic) < 0) {
1265 perror("ioctl VIDIOCSPICT");
1268 /* InitConfig function */
1269 void
1270 InitConfig(void)
1272 int i;
1274 ParseRCFile(usrConfFile, wmtv_keys);
1275 ParseRCFile2(usrConfFile);
1277 if (norcfile) {
1278 ParseRCFile(sysConfFile, wmtv_keys);
1279 ParseRCFile2(sysConfFile);
1281 if (norcfile) {
1282 fprintf(stderr, "wmtv: error - config file not found\n");
1283 exit(1);
1287 if (maxpreset != NULL)
1288 maxpst = atoi(maxpreset) - 1;
1289 else
1290 maxpst = 1;
1292 if ((tpst) != atoi(maxpreset)) {
1293 fprintf(stderr, "wmtv: error - maxpreset value does not match total channel value\n");
1294 exit(1);
1296 if ((tfd = open(dev, O_RDWR)) < 0) {
1297 perror("open failed");
1299 card_present = TRUE;
1301 if (norm)
1302 for (i=0; i < CHAN_NAMES; i++) {
1303 if (!strcmp(chan_names[i].cname, norm)) {
1304 freqnorm = chan_names[i].cind;
1308 if (freqnorm == -1) {
1309 fprintf(stderr, "wmtv: error - set freqnorm in config file\n");
1310 exit(1);
1313 if (ioctl(tfd, VIDIOCGCAP, &vcap) < 0) {
1314 perror("ioctl VIDIOCGCAP");
1317 if (!(vcap.type & VID_TYPE_SCALES)) {
1318 fprintf(stderr, "%s: video device does not support scalling\n", progname);
1319 exit(1);
1321 if (!(vcap.type & VID_TYPE_CLIPPING)) {
1322 fprintf(stderr, "%s: video device does not support clipping\n", progname);
1325 if (fullscreen) {
1326 fswidth = atoi(strtok(fullscreen, "x\n"));
1327 fsheight = atoi(strtok(NULL, "x\n"));
1329 else {
1330 fswidth = 640;
1331 fsheight = 480;
1334 if (source) {
1335 for (i=0; i < vcap.channels; i++) {
1336 vchn.channel = i;
1337 if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0) {
1338 perror("ioctl VIDIOCGCHAN");
1340 if (!strcmp(vchn.name, source)) {
1341 if (vchn.tuners)
1342 cnotune = 0;
1343 else
1344 cnotune = 1;
1346 vsource = 1;
1347 tvsource = vchn.channel;
1349 if ((ioctl(tfd, VIDIOCSCHAN, &vchn)) < 0)
1350 perror("ioctl VIDIOCSCHAN");
1353 if (!vsource)
1354 fprintf(stderr, "wmtv: invalid source in config file\n");
1357 if (mode) {
1358 if (!cnotune) {
1359 vtun.tuner = 0;
1360 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
1361 perror("ioctl VIDIOCGTUNER");
1364 if (!strcmp(mode, "pal")) {
1365 if (vtun.flags & VIDEO_TUNER_PAL) {
1366 vtun.mode = VIDEO_MODE_PAL;
1367 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1368 perror("ioctl VIDIOCSTUNER");
1372 if (!strcmp(mode, "ntsc")) {
1373 if (vtun.flags & VIDEO_TUNER_NTSC) {
1374 vtun.mode = VIDEO_MODE_NTSC;
1375 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1376 perror("ioctl VIDIOCSTUNER");
1380 if (!strcmp(mode, "secam")) {
1381 if (vtun.flags & VIDEO_TUNER_SECAM) {
1382 vtun.mode = VIDEO_MODE_SECAM;
1383 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1384 perror("ioctl VIDIOCSTUNER");
1391 for (i=0; i < vcap.audios; i++) {
1392 vaud.audio = i;
1393 if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0) {
1394 perror("ioctl VIDIOCGAUDIO");
1396 if (!(vaud.flags & VIDEO_AUDIO_MUTE)) {
1397 vaud.flags |= VIDEO_AUDIO_MUTE;
1398 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) {
1399 perror("ioctl VIDIOCSAUDIO");
1404 if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
1405 perror("ioctl VIDIOCGFBUF");
1409 /* GetFrameBuffer function */
1410 void
1411 GetFrameBuffer(void)
1413 #if 0
1414 void *baseaddr = NULL;
1415 int evbr, erbr, flr = 0;
1416 int bankr, memr, depth;
1417 int i, n;
1418 int bytesperline, bitsperpixel;
1419 XPixmapFormatValues *pf;
1420 #endif
1422 if (!XGetWindowAttributes(display, DefaultRootWindow(display), &Winattr)) {
1423 fprintf(stderr, "wmtv: error getting winattr of root\n");
1426 #if 0
1427 depth = Winattr.depth;
1429 if (XF86DGAQueryExtension(display, &evbr, &erbr)) {
1430 XF86DGAQueryDirectVideo(display, XDefaultScreen(display), &flr);
1431 if (flr & XF86DGADirectPresent) {
1432 XF86DGAGetVideoLL(display, XDefaultScreen(display),
1433 (int *) &baseaddr, &bytesperline, &bankr, &memr);
1436 else {
1437 fprintf(stderr, "wmtv: error - XF86DGA Extensions not available\n");
1438 exit(1);
1442 pf = XListPixmapFormats(display, &n);
1443 for (i=0; i < n; i++) {
1444 if (pf[i].depth == depth) {
1445 depth = pf[i].bits_per_pixel;
1446 break;
1450 bitsperpixel = (depth+7) & 0xf8;
1451 bytesperline *= bitsperpixel/8;
1453 vfb.base = baseaddr;
1454 vfb.height = Winattr.height;
1455 vfb.width = Winattr.width;
1456 vfb.depth = bitsperpixel;
1457 vfb.bytesperline = bytesperline;
1459 if (Winattr.depth == 15)
1460 vfb.depth = 15;
1462 if (ioctl(tfd, VIDIOCSFBUF, &vfb) < 0) {
1463 perror("ioctl VIDIOCSFBUF");
1465 #endif
1469 /* DoFullScreen function */
1470 void
1471 DoFullScreen(void)
1473 int i;
1474 int evbr, erbr = 0;
1475 int rx, ry;
1476 unsigned long back_pix, fore_pix;
1477 unsigned int borderwidth = 0;
1479 Window junkwin;
1480 XSizeHints fmsizehints;
1481 XWMHints fmxwmhints;
1482 XGCValues gcv;
1483 unsigned long gcm;
1484 unsigned long valuemask;
1486 XSetWindowAttributes fmWinattr;
1487 XWindowAttributes fmwinattr;
1490 ccapt = 0;
1491 if (ioctl (tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1492 perror("ioctl VIDIOCCAPTURE");
1495 fmsizehints.x = 0;
1496 fmsizehints.y = 0;
1497 fmsizehints.width = fswidth;
1498 fmsizehints.height = fsheight;
1499 fmsizehints.max_width = vcap.maxwidth;
1500 fmsizehints.max_height = vcap.maxheight;
1501 fmsizehints.min_width = fswidth;
1502 fmsizehints.min_height = fsheight;
1503 fmsizehints.flags = (USPosition | USSize | PSize | PMinSize | PMaxSize);
1505 valuemask = 0;
1507 back_pix = WhitePixel(display, DefaultScreen(display));
1508 fore_pix = BlackPixel(display, DefaultScreen(display));
1510 fmwin = XCreateWindow(display, DefaultRootWindow(display), fmsizehints.x,
1511 fmsizehints.y, fmsizehints.width, fmsizehints.height,
1512 borderwidth, CopyFromParent, InputOutput,
1513 CopyFromParent, valuemask, &fmWinattr);
1516 XSetWMNormalHints(display, fmwin, &fmsizehints);
1518 gcm = (GCForeground | GCBackground | GCGraphicsExposures);
1519 gcv.foreground = fore_pix;
1520 gcv.background = back_pix;
1521 gcv.graphics_exposures = 0;
1523 fmGC = XCreateGC(display, DefaultRootWindow(display), gcm, &gcv);
1525 XSelectInput(display, fmwin, ButtonPressMask | ExposureMask |
1526 ButtonReleaseMask | PointerMotionMask |
1527 StructureNotifyMask | VisibilityChangeMask | KeyPressMask );
1529 fmxwmhints.flags = StateHint;
1530 fmxwmhints.initial_state = NormalState;
1532 XSetWMHints(display, fmwin, &fmxwmhints);
1535 if (XF86VidModeQueryExtension(display, &evbr, &erbr)) {
1536 vidmode = TRUE;
1538 else {
1539 fprintf(stderr, "wmtv: xf86mode extension not present\n");
1540 fprintf(stderr, " switch disabled\n");
1544 XMapWindow(display, fmwin);
1546 usleep(50000L);
1547 if (!XGetWindowAttributes(display, fmwin, &fmwinattr)) {
1548 fprintf(stderr, "wmtv: error getting winattr of fmwin\n");
1551 usleep(50000L);
1552 if (!XTranslateCoordinates(display, fmwin, DefaultRootWindow(display),
1553 -fmwinattr.border_width,
1554 -fmwinattr.border_width,
1555 &rx, &ry, &junkwin)) {
1556 fprintf(stderr, "wmtv: error translating coordinates for fmwin");
1559 vswin.width = fswidth;
1560 vswin.height = fsheight;
1561 vswin.x = fmsizehints.x + rx;
1562 vswin.y = fmsizehints.y + ry;
1563 vswin.clipcount = 0;
1565 if (ioctl(tfd, VIDIOCSWIN, &vswin) < 0) {
1566 perror("ioctl VIDIOCSWIN");
1569 ccapt = 1;
1570 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1571 perror("ioctl VIDIOCCAPTURE");
1573 fmode = TRUE;
1575 if (vidmode) {
1576 XF86VidModeGetModeLine(display, XDefaultScreen(display), &dcret, &scmode);
1577 XF86VidModeGetAllModeLines(display, XDefaultScreen(display), &tml, &modelines);
1579 for (i=0; i < tml; i++) {
1580 if ((modelines[i]->hdisplay == fswidth) &&
1581 (modelines[i]->vdisplay == fsheight)) {
1582 fullscreenmode = modelines[i];
1583 mode_present = TRUE;
1584 break;
1588 if (!mode_present) {
1589 fprintf(stderr, "wmtv: mode line for resolution %d x %d not found\n", vcap.maxwidth, vcap.maxheight);
1592 XRaiseWindow(display, fmwin);
1593 if (mode_present) {
1595 XF86VidModeSwitchToMode(display, XDefaultScreen(display), fullscreenmode);
1596 XF86VidModeSetViewPort(display, XDefaultScreen(display), vswin.x, vswin.y);
1597 XGrabPointer(display, fmwin, True, 0, GrabModeAsync, GrabModeAsync,
1598 fmwin, None, CurrentTime);
1604 /* RetScreen function */
1605 void
1606 RetScreen()
1608 int i;
1609 XF86VidModeModeInfo *scm = NULL;
1611 ccapt = 0;
1612 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt)) {
1613 perror("ioctl VIDIOCCAPTURE");
1616 if (mode_present) {
1617 for (i = 0; i < tml; i++) {
1618 if ((modelines[i]->hdisplay == Winattr.width) &&
1619 (modelines[i]->vdisplay==Winattr.height))
1620 scm = modelines[i];
1623 scm->dotclock = dcret;
1624 scm->hdisplay = scmode.hdisplay;
1625 scm->hsyncstart = scmode.hsyncstart;
1626 scm->hsyncend = scmode.hsyncend;
1627 scm->htotal = scmode.htotal;
1628 scm->vdisplay = scmode.vdisplay;
1629 scm->vsyncstart = scmode.vsyncstart;
1630 scm->vsyncend = scmode.vsyncend;
1631 scm->vtotal = scmode.vtotal;
1632 scm->flags = scmode.flags;
1634 scm->privsize = scmode.privsize;
1635 scm->private = scmode.private;
1638 XClearWindow(display, fmwin);
1639 XFreeGC(display, fmGC);
1640 XMapRaised(display, fmwin);
1641 XUnmapWindow(display, fmwin);
1642 XUngrabPointer(display, CurrentTime);
1644 else {
1645 XClearWindow(display, fmwin);
1646 XFreeGC(display, fmGC);
1647 XMapRaised(display, fmwin);
1648 XUnmapWindow(display, fmwin);
1651 if (vidmode && mode_present) {
1652 XF86VidModeSwitchToMode(display, XDefaultScreen(display), scm);
1653 vidmode = FALSE;
1655 fmode = FALSE;
1656 mode_present = FALSE;
1658 ccapt = 1;
1659 if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0) {
1660 perror("ioctl VIDIOCSWIN");
1663 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1664 perror("ioctl VIDIOCCAPTURE");
1666 RedrawWindow();
1669 /* GrabImage function */
1670 void
1671 GrabImage(void)
1675 /* Usage function */
1676 void
1677 Usage(void)
1679 fprintf(stderr, "\n");
1680 fprintf(stderr, "wmtv v%s, Copyright (c) 1999 Wee Liang <wliang@tartarus.uwa.edu.au>\n", VERSION);
1681 fprintf(stderr, "usage: wmtv [%s]\n", OPTIONS);
1682 fprintf(stderr, " -c, --device <file>\tsets video4linux device to use\n");
1683 fprintf(stderr, " -d, --display <host:vs>\tsets display name\n");
1684 fprintf(stderr, " -g, --geometry <{+-}XP{+-}YP>\tsets geometry\n");
1685 fprintf(stderr, " -b, --bpp\t\t\tdisplay color depth\n");
1686 fprintf(stderr, " -e, --exe <filename>\t\tprogram to execute\n");
1687 fprintf(stderr, " -v, --version\t\t\tprints version information\n");
1688 fprintf(stderr, " -h, --help\t\t\tprints this message\n");
1689 fprintf(stderr, "\n");
1693 /* Version function */
1694 void
1695 Version(void)
1697 fprintf(stderr, "wmtv version %s\n", VERSION);