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)
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
33 #include <sys/ioctl.h>
35 #include <sys/types.h>
37 #include <libv4l1-videodev.h>
38 #include <linux/soundcard.h>
41 #include <X11/Xutil.h>
43 #include <X11/StringDefs.h>
44 #include <X11/XKBlib.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"
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 */
77 #define OPTIONS "hvd:g:e:b:c:"
83 #ifndef GLOBALCONFFILE
84 #define GLOBALCONFFILE "/etc/wmtvrc"
87 /* Global Variables */
90 int card_present
= FALSE
;
91 int ntfb_status
= SETOFF
;
92 char *maxpreset
= NULL
;
94 int mode_present
= FALSE
;
116 pid_t child_pid
= -1;
119 unsigned long ccrfreq
;
126 char *fullscreen
= NULL
;
128 char *cname
[MAXCHAN
];
129 char *comment
[MAXCHAN
];
132 char *dev
= "/dev/video";
134 char *sysConfFile
= GLOBALCONFFILE
;
137 int wmtv_mask_width
= 64;
138 int wmtv_mask_height
= 64;
139 char wmtv_mask_bits
[64*64];
142 int but_pressed
= FALSE
;
143 int but_clicked
= FALSE
;
149 rckeys wmtv_keys
[] = {
150 { "freqnorm", &norm
},
151 { "source", &source
},
152 { "maxpreset", &maxpreset
},
154 { "fullscreen", &fullscreen
},
159 XWindowAttributes Winattr
;
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 */
185 void FineTuneUp(void);
186 void FineTuneDown(void);
191 void ButtonDown(int);
193 void MuteAudio(void);
194 void UnMuteAudio(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);
213 sigchld_handler(int i
)
216 pid
= waitpid((pid_t
)-1, NULL
, WNOHANG
);
217 while (pid
>(pid_t
)0) {
218 if (pid
== child_pid
) {
222 pid
= waitpid((pid_t
)-1, NULL
, WNOHANG
);
231 sa
.sa_handler
= &sigchld_handler
;
232 sigemptyset(&sa
.sa_mask
);
233 sa
.sa_flags
= SA_RESTART
;
234 sigaction(SIGCHLD
, &sa
, NULL
);
238 expand_format(char *format
, char *letters
, char **expansions
)
241 unsigned int string_pos
= 0;
243 size
= strlen(format
)+1;
244 string
= (char *)malloc(size
*sizeof(char));
245 for (; *format
!= '\0'; format
++) {
246 if (*format
== '%') {
248 if (*format
!= '%') {
250 for (i
= 0; letters
[i
] != '\0'; i
++) {
251 if (letters
[i
] == *format
)
254 if (letters
[i
] != '\0') {
255 unsigned int expansion_size
;
256 expansion_size
= strlen(expansions
[i
]);
257 while (string_pos
+expansion_size
+1 > size
) {
259 string
= realloc(string
, size
*sizeof(char));
261 memcpy(string
+string_pos
, expansions
[i
], expansion_size
);
262 string_pos
+= expansion_size
;
270 while (string_pos
+1+1 > size
) {
272 string
= realloc(string
, size
*sizeof(char));
274 string
[string_pos
] = *format
;
277 string
[string_pos
] = '\0';
283 main(int argc
, char *argv
[])
286 int pressed_button
= -1;
288 static struct option long_options
[] = {
289 {"device", 1, 0, 'c'},
290 {"display", 1, 0, 'd'},
291 {"geometry", 1, 0, 'g'},
295 {"version", 0, 0, 'v'},
299 progname
= strdup(argv
[0]);
302 char *home
= getenv("HOME");
305 fprintf(stderr
, "wmtv: $HOME should be set.\n");
309 usrConfFile
= (char *)malloc(sizeof(char)*(strlen(home
)+8+1));
310 strcpy(usrConfFile
, home
);
311 strcat(usrConfFile
, "/.wmtvrc");
316 c
= getopt_long (argc
, argv
, OPTIONS
, long_options
, &opind
);
324 fprintf(stderr, "wmtv: option - %s", long_options[opind].name);
326 fprintf(stderr, " with arg %s", optarg);
331 display_name
= strdup(optarg
);
334 geometry
= strdup(optarg
);
337 exe
= strdup(optarg
);
338 /* strcat(exe, " &"); */
341 dev
= strdup(optarg
);
344 fprintf(stderr
, "wmtv: option not implemented yet\n");
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 */
376 if (ntfb_status
== SETOFF
) {
384 while (XPending(display
))
386 XNextEvent(display
, &Event
);
387 switch (Event
.type
) {
392 XCloseDisplay(display
);
394 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
395 perror("ioctl VIDIOCCAPTURE");
402 if ((Event
.xany
.window
== fmwin
) && fmode
) {
406 pressed_button
= CheckMouseRegion (Event
.xbutton
.x
, Event
.xbutton
.y
);
407 switch (pressed_button
) {
410 t_lc
= Event
.xbutton
.time
;
415 if (ntfb_status
== SETUNE
) {
416 switch (Event
.xbutton
.button
) {
419 while (timebutton
== 1)
420 if (isource
== TELEVISION
)
424 if (isource
== TELEVISION
)
429 else if (ntfb_status
== SETON
)
434 if (ntfb_status
== SETUNE
) {
435 switch (Event
.xbutton
.button
) {
439 if (isource
== TELEVISION
)
443 if (isource
== TELEVISION
)
448 else if (ntfb_status
== SETON
)
453 switch (Event
.xbutton
.button
) {
475 switch (pressed_button
) {
479 if (Event
.xbutton
.time
- t_lc
>= 900) {
485 if (ntfb_status
== SETOFF
) {
486 if (child_pid
== -1) {
491 else if (ntfb_status
== SETON
) {
493 ntfb_status
= SETUNE
;
494 copyXPMArea(96, 79, 11, 7, 6, 50);
495 RedrawWindowXYWH(6, 50, 11, 7);
498 ntfb_status
= SETOFF
;
504 else if (ntfb_status
== SETUNE
) {
506 ftune
[cchannel
] = (rfreq
- ccrfreq
);
507 /* fprintf(stderr, "wmtv: finetune offset = %ld\n", ftune[cchannel]); */
508 WriteRCFile(usrConfFile
, wmtv_keys
);
510 DrawPresetChan(cchannel
);
513 ntfb_status
= SETOFF
;
522 if (ntfb_status
== SETUNE
)
527 if (ntfb_status
== SETUNE
)
532 switch (Event
.xbutton
.button
) {
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
)) {
544 char *letters
= "#nf";
545 char *(expansions
[3]);
546 ntfb_status
= SETOFF
;
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
);
556 if (child_pid
== (pid_t
) 0) {
562 execv("/bin/sh", argv
);
568 pid
= waitpid(child_pid
, NULL
, WNOHANG
);
573 /* printf("Returned pid:\n"); */
579 if (pid
== (pid_t
) 0) {
580 execlp("xawtv", "xawtv", "&", (char *) 0);
583 else if (pid
< (pid_t
) 0) {
589 if (waitpid(pid
, NULL
, 0) < 0) {
601 t_lc
= Event
.xbutton
.time
;
602 x_lc
= Event
.xbutton
.x
;
603 y_lc
= Event
.xbutton
.y
;
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
)) {
623 t_lc
= Event
.xbutton
.time
;
624 x_lc
= Event
.xbutton
.x
;
625 y_lc
= Event
.xbutton
.y
;
638 case VisibilityNotify
:
639 switch(Event
.xvisibility
.state
) {
640 case VisibilityFullyObscured
:
642 if (tfd
&& (ntfb_status
!= SETOFF
) && !fmode
) {
643 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
644 perror("ioctl VIDIOCCAPTURE");
648 case VisibilityPartiallyObscured
:
650 if (tfd
&& (ntfb_status
!= SETOFF
) && !fmode
) {
651 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
652 perror("ioctl VIDIOCCAPTURE");
656 case VisibilityUnobscured
:
658 if (tfd
&& (ntfb_status
!= SETOFF
) && !fmode
) {
659 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
660 perror("ioctl VIDIOCCAPTURE");
668 if ((Event
.xany
.window
== fmwin
) && fmode
) {
669 switch(XkbKeycodeToKeysym(display
, Event
.xkey
.keycode
, 0, 0)) {
671 if (isource
== TELEVISION
)
675 if (isource
== TELEVISION
)
710 /* ButtonDown function */
712 ButtonDown(int button
)
716 copyXPMArea(79, 100, 12, 11, 47, 48);
717 RedrawWindowXYWH (47, 48, 12, 11);
720 copyXPMArea(55, 100, 12, 11, 23, 48);
721 RedrawWindowXYWH(35, 48, 12, 11);
724 copyXPMArea(67, 100, 12, 11, 35, 48);
725 RedrawWindowXYWH(35, 48, 12, 11);
733 /* ButtonUp function */
739 copyXPMArea(79, 88, 12, 11, 47, 48);
740 RedrawWindowXYWH(47, 48, 12, 11);
743 copyXPMArea(55, 88, 12, 11, 23, 48);
744 RedrawWindowXYWH(23, 48, 12, 11);
747 copyXPMArea(67, 88, 12, 11, 35, 48);
748 RedrawWindowXYWH(35, 48, 12, 11);
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
,"could'nt start v4l-conf\n");
785 default: /* non-zero return */
786 fprintf(stderr
,"v4l-conf had some trouble, "
787 "trying to continue anyway\n");
789 /* End of "stolen" part */
802 vclip
[0].x
= 0; /* Clipping Rect 1 */
805 vclip
[0].height
= 39;
806 vclip
[1].x
= 59; /* Clipping Rect 2 */
809 vclip
[1].height
= 39;
814 vchn
.channel
= tvsource
;
815 vaud
.audio
= tvsource
;
820 isource
= TELEVISION
;
821 else if (*p
== 'C') {
825 compchannel
= atoi(p
);
832 if (ioctl(tfd
, VIDIOCGTUNER
, &vtun
) < 0)
833 perror("ioctl VIDIOCGTUNER");
834 if (vtun
.flags
& VIDEO_TUNER_LOW
)
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
];
861 DrawPresetChan(cchannel
);
863 else if (isource
== COMPOSITE
) {
864 DrawPresetChan(compchannel
);
866 else if (isource
== SVIDEO
) {
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");
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");
898 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0)
899 perror("ioctl VIDIOCCAPTURE");
901 vaud
.audio
= tvsource
;
903 vaud
.flags
|= VIDEO_AUDIO_MUTE
;
905 if (vchn
.flags
& VIDEO_VC_AUDIO
) {
906 if (ioctl(tfd
, VIDIOCSAUDIO
, &vaud
) < 0)
907 perror("ioctl VIDIOCSAUDIO");
911 copyXPMArea(66, 79, 11, 7, 6, 50);
912 RedrawWindowXYWH(6, 50, 11, 7);
916 /* VolumeUp function */
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 */
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 */
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");
964 /* UnMuteAudio function */
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");
979 /* ScanUp function */
985 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
986 perror("ioctl VIDIOCSFREQ");
990 if (ioctl(tfd
, VIDIOCGTUNER
, &vtun
) < 0) {
991 perror("ioctl VIDIOCGTUNER");
993 if (vtun
.signal
== 0xFFFF) {
1000 /* ScanDown function */
1006 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
1007 perror("ioctl VIDIOCSFREQ");
1011 if (ioctl(tfd
, VIDIOCGTUNER
, &vtun
) < 0) {
1012 perror("ioctl VIDIOCGTUNER");
1014 if (vtun
.signal
== 0xFFFF) {
1020 /* FineTuneUp function */
1025 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
1026 perror("ioctl VIDIOCSFREQ");
1031 /* FineTuneDown function */
1036 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
1037 perror("ioctl VIDIOCSFREQ");
1042 /* ChanUp function */
1047 if (cchannel
< maxpst
)
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
];
1057 DrawPresetChan(cchannel
);
1058 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0)
1059 perror("ioctl VIDIOCSFREQ");
1063 /* ChanDown function */
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
];
1078 DrawPresetChan(cchannel
);
1079 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0)
1080 perror("ioctl VIDIOCSFREQ");
1084 /* DrawPresetChan function */
1086 DrawPresetChan(int cchannel
)
1093 if (isource
== TELEVISION
) {
1094 sprintf(temp
, "%02d", cchannel
+1);
1097 copyXPMArea(66, 79, 5, 7, k
, 50);
1103 copyXPMArea((*p
-'0')*6 + 1, 79, 5, 7, k
, 50);
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 */
1125 ParseRCFile(const char *filename
, rckeys
*keys
)
1129 char *tokens
= " =\t\n";
1133 if ((fp
= fopen(filename
, "r")) == NULL
) {
1134 fprintf(stderr
, "wmtv: %s\n", strerror(errno
));
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
);
1156 /* ParseRCFile2 function */
1158 ParseRCFile2(const char *filename
)
1161 char temp
[128], name
[128];
1165 if ((fp
= fopen(filename
, "r")) == NULL
) {
1166 fprintf(stderr
, "wmtv: %s\n", strerror(errno
));
1171 while (fgets(temp
, 128, fp
)) {
1172 if (*temp
!= '\n') {
1175 if(sscanf(temp
, " %s %n(%ld) %n", name
, &len
, &ftune
[i
], &len
)>=1) {
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
++) {
1190 else if (strchr(temp
, '[')) {
1200 /* WriteRCFile function */
1202 WriteRCFile(const char *filename
, rckeys
*keys
)
1208 if ((fp
= fopen(filename
, "w")) == NULL
) {
1209 fprintf(stderr
, "wmtv: %s\n", strerror(errno
));
1213 for (key
=0; keys
[key
].label
; key
++)
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
]);
1226 /* InitPalette function */
1230 if (ioctl(tfd
, VIDIOCGFBUF
, &vfb
) < 0) {
1231 perror ("ioctl VIDIOCGFBUF");
1234 if (vfb
.base
== NULL
) {
1235 fprintf(stderr
, "wmtv: no physical frame buffer access\n");
1240 if (ioctl(tfd
, VIDIOCGPICT
, &vpic
) < 0) {
1241 perror("ioctl VIDIOCGPICT");
1243 vpic
.depth
= vfb
.depth
;
1244 switch(vpic
.depth
) {
1246 vpic
.palette
= VIDEO_PALETTE_HI240
;
1249 vpic
.palette
= VIDEO_PALETTE_RGB555
;
1252 vpic
.palette
= VIDEO_PALETTE_RGB565
;
1255 vpic
.palette
= VIDEO_PALETTE_RGB24
;
1258 vpic
.palette
= VIDEO_PALETTE_RGB32
;
1261 fprintf(stderr
, "wmtv: unsupported depth %d\n", vpic
.depth
);
1264 if (ioctl(tfd
, VIDIOCSPICT
, &vpic
) < 0) {
1265 perror("ioctl VIDIOCSPICT");
1268 /* InitConfig function */
1274 ParseRCFile(usrConfFile
, wmtv_keys
);
1275 ParseRCFile2(usrConfFile
);
1278 ParseRCFile(sysConfFile
, wmtv_keys
);
1279 ParseRCFile2(sysConfFile
);
1282 fprintf(stderr
, "wmtv: error - config file not found\n");
1287 if (maxpreset
!= NULL
)
1288 maxpst
= atoi(maxpreset
) - 1;
1292 if ((tpst
) != atoi(maxpreset
)) {
1293 fprintf(stderr
, "wmtv: error - maxpreset value does not match total channel value\n");
1296 if ((tfd
= open(dev
, O_RDWR
)) < 0) {
1297 perror("open failed");
1299 card_present
= TRUE
;
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");
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
);
1321 if (!(vcap
.type
& VID_TYPE_CLIPPING
)) {
1322 fprintf(stderr
, "%s: video device does not support clipping\n", progname
);
1326 fswidth
= atoi(strtok(fullscreen
, "x\n"));
1327 fsheight
= atoi(strtok(NULL
, "x\n"));
1335 for (i
=0; i
< vcap
.channels
; i
++) {
1337 if (ioctl(tfd
, VIDIOCGCHAN
, &vchn
) < 0) {
1338 perror("ioctl VIDIOCGCHAN");
1340 if (!strcmp(vchn
.name
, source
)) {
1347 tvsource
= vchn
.channel
;
1349 if ((ioctl(tfd
, VIDIOCSCHAN
, &vchn
)) < 0)
1350 perror("ioctl VIDIOCSCHAN");
1354 fprintf(stderr
, "wmtv: invalid source in config file\n");
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
++) {
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 */
1411 GetFrameBuffer(void)
1414 void *baseaddr
= NULL
;
1415 int evbr
, erbr
, flr
= 0;
1416 int bankr
, memr
, depth
;
1418 int bytesperline
, bitsperpixel
;
1419 XPixmapFormatValues
*pf
;
1422 if (!XGetWindowAttributes(display
, DefaultRootWindow(display
), &Winattr
)) {
1423 fprintf(stderr
, "wmtv: error getting winattr of root\n");
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
);
1437 fprintf(stderr
, "wmtv: error - XF86DGA Extensions not available\n");
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
;
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)
1462 if (ioctl(tfd
, VIDIOCSFBUF
, &vfb
) < 0) {
1463 perror("ioctl VIDIOCSFBUF");
1469 /* DoFullScreen function */
1476 unsigned long back_pix
, fore_pix
;
1477 unsigned int borderwidth
= 0;
1480 XSizeHints fmsizehints
;
1481 XWMHints fmxwmhints
;
1484 unsigned long valuemask
;
1486 XSetWindowAttributes fmWinattr
;
1487 XWindowAttributes fmwinattr
;
1491 if (ioctl (tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
1492 perror("ioctl VIDIOCCAPTURE");
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
);
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
)) {
1539 fprintf(stderr
, "wmtv: xf86mode extension not present\n");
1540 fprintf(stderr
, " switch disabled\n");
1544 XMapWindow(display
, fmwin
);
1547 if (!XGetWindowAttributes(display
, fmwin
, &fmwinattr
)) {
1548 fprintf(stderr
, "wmtv: error getting winattr of fmwin\n");
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");
1570 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
1571 perror("ioctl VIDIOCCAPTURE");
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
;
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
);
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 */
1609 XF86VidModeModeInfo
*scm
= NULL
;
1612 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
)) {
1613 perror("ioctl VIDIOCCAPTURE");
1617 for (i
= 0; i
< tml
; i
++) {
1618 if ((modelines
[i
]->hdisplay
== Winattr
.width
) &&
1619 (modelines
[i
]->vdisplay
==Winattr
.height
))
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
);
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
);
1656 mode_present
= FALSE
;
1659 if (ioctl(tfd
, VIDIOCSWIN
, &vwin
) < 0) {
1660 perror("ioctl VIDIOCSWIN");
1663 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
1664 perror("ioctl VIDIOCCAPTURE");
1669 /* GrabImage function */
1675 /* Usage function */
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 */
1697 fprintf(stderr
, "wmtv version %s\n", VERSION
);