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/keysym.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 */
89 int card_present
= FALSE
;
90 int ntfb_status
= SETOFF
;
91 char *maxpreset
= NULL
;
93 int mode_present
= FALSE
;
115 pid_t child_pid
= -1;
118 unsigned long ccrfreq
;
125 char *fullscreen
= NULL
;
127 char *cname
[MAXCHAN
];
128 char *comment
[MAXCHAN
];
131 char *dev
= "/dev/video";
133 char *sysConfFile
= GLOBALCONFFILE
;
136 int wmtv_mask_width
= 64;
137 int wmtv_mask_height
= 64;
138 char wmtv_mask_bits
[64*64];
141 int but_pressed
= FALSE
;
142 int but_clicked
= FALSE
;
148 rckeys wmtv_keys
[] = {
149 { "freqnorm", &norm
},
150 { "source", &source
},
151 { "maxpreset", &maxpreset
},
153 { "fullscreen", &fullscreen
},
158 XWindowAttributes Winattr
;
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 */
184 void FineTuneUp(void);
185 void FineTuneDown(void);
190 void ButtonDown(int);
192 void MuteAudio(void);
193 void UnMuteAudio(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);
212 sigchld_handler(int i
)
215 pid
= waitpid((pid_t
)-1, NULL
, WNOHANG
);
216 while (pid
>(pid_t
)0) {
217 if (pid
== child_pid
) {
221 pid
= waitpid((pid_t
)-1, NULL
, WNOHANG
);
230 sa
.sa_handler
= &sigchld_handler
;
231 sigemptyset(&sa
.sa_mask
);
232 sa
.sa_flags
= SA_RESTART
;
233 sigaction(SIGCHLD
, &sa
, NULL
);
237 expand_format(char *format
, char *letters
, char **expansions
)
240 unsigned int string_pos
= 0;
242 size
= strlen(format
)+1;
243 string
= (char *)malloc(size
*sizeof(char));
244 for (; *format
!= '\0'; format
++) {
245 if (*format
== '%') {
247 if (*format
!= '%') {
249 for (i
= 0; letters
[i
] != '\0'; i
++) {
250 if (letters
[i
] == *format
)
253 if (letters
[i
] != '\0') {
254 unsigned int expansion_size
;
255 expansion_size
= strlen(expansions
[i
]);
256 while (string_pos
+expansion_size
+1 > size
) {
258 string
= realloc(string
, size
*sizeof(char));
260 memcpy(string
+string_pos
, expansions
[i
], expansion_size
);
261 string_pos
+= expansion_size
;
269 while (string_pos
+1+1 > size
) {
271 string
= realloc(string
, size
*sizeof(char));
273 string
[string_pos
] = *format
;
276 string
[string_pos
] = '\0';
282 main(int argc
, char *argv
[])
285 int pressed_button
= -1;
287 static struct option long_options
[] = {
288 {"device", 1, 0, 'c'},
289 {"display", 1, 0, 'd'},
290 {"geometry", 1, 0, 'g'},
294 {"version", 0, 0, 'v'},
298 progname
= strdup(argv
[0]);
301 char *home
= getenv("HOME");
304 fprintf(stderr
, "wmtv: $HOME should be set.\n");
308 usrConfFile
= (char *)malloc(sizeof(char)*(strlen(home
)+8+1));
309 strcpy(usrConfFile
, home
);
310 strcat(usrConfFile
, "/.wmtvrc");
315 c
= getopt_long (argc
, argv
, OPTIONS
, long_options
, &opind
);
323 fprintf(stderr, "wmtv: option - %s", long_options[opind].name);
325 fprintf(stderr, " with arg %s", optarg);
330 display_name
= strdup(optarg
);
333 geometry
= strdup(optarg
);
336 exe
= strdup(optarg
);
337 /* strcat(exe, " &"); */
340 dev
= strdup(optarg
);
343 fprintf(stderr
, "wmtv: option not implemented yet\n");
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 */
375 if (ntfb_status
== SETOFF
) {
383 while (XPending(display
))
385 XNextEvent(display
, &Event
);
386 switch (Event
.type
) {
391 XCloseDisplay(display
);
393 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
394 perror("ioctl VIDIOCCAPTURE");
401 if ((Event
.xany
.window
== fmwin
) && fmode
) {
405 pressed_button
= CheckMouseRegion (Event
.xbutton
.x
, Event
.xbutton
.y
);
406 switch (pressed_button
) {
409 t_lc
= Event
.xbutton
.time
;
414 if (ntfb_status
== SETUNE
) {
415 switch (Event
.xbutton
.button
) {
418 while (timebutton
== 1)
419 if (isource
== TELEVISION
)
423 if (isource
== TELEVISION
)
428 else if (ntfb_status
== SETON
)
433 if (ntfb_status
== SETUNE
) {
434 switch (Event
.xbutton
.button
) {
438 if (isource
== TELEVISION
)
442 if (isource
== TELEVISION
)
447 else if (ntfb_status
== SETON
)
452 switch (Event
.xbutton
.button
) {
474 switch (pressed_button
) {
478 if (Event
.xbutton
.time
- t_lc
>= 900) {
484 if (ntfb_status
== SETOFF
) {
485 if (child_pid
== -1) {
490 else if (ntfb_status
== SETON
) {
492 ntfb_status
= SETUNE
;
493 copyXPMArea(96, 79, 11, 7, 6, 50);
494 RedrawWindowXYWH(6, 50, 11, 7);
497 ntfb_status
= SETOFF
;
503 else if (ntfb_status
== SETUNE
) {
505 ftune
[cchannel
] = (rfreq
- ccrfreq
);
506 /* fprintf(stderr, "wmtv: finetune offset = %ld\n", ftune[cchannel]); */
507 WriteRCFile(usrConfFile
, wmtv_keys
);
509 DrawPresetChan(cchannel
);
512 ntfb_status
= SETOFF
;
521 if (ntfb_status
== SETUNE
)
526 if (ntfb_status
== SETUNE
)
531 switch (Event
.xbutton
.button
) {
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
)) {
543 char *letters
= "#nf";
544 char *(expansions
[3]);
545 ntfb_status
= SETOFF
;
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
);
555 if (child_pid
== (pid_t
) 0) {
561 execv("/bin/sh", argv
);
567 pid
= waitpid(child_pid
, NULL
, WNOHANG
);
572 /* printf("Returned pid:\n"); */
578 if (pid
== (pid_t
) 0) {
579 execlp("xawtv", "xawtv", "&", (char *) 0);
582 else if (pid
< (pid_t
) 0) {
588 if (waitpid(pid
, NULL
, 0) < 0) {
600 t_lc
= Event
.xbutton
.time
;
601 x_lc
= Event
.xbutton
.x
;
602 y_lc
= Event
.xbutton
.y
;
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
)) {
622 t_lc
= Event
.xbutton
.time
;
623 x_lc
= Event
.xbutton
.x
;
624 y_lc
= Event
.xbutton
.y
;
637 case VisibilityNotify
:
638 switch(Event
.xvisibility
.state
) {
639 case VisibilityFullyObscured
:
641 if (tfd
&& (ntfb_status
!= SETOFF
) && !fmode
) {
642 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
643 perror("ioctl VIDIOCCAPTURE");
647 case VisibilityPartiallyObscured
:
649 if (tfd
&& (ntfb_status
!= SETOFF
) && !fmode
) {
650 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
651 perror("ioctl VIDIOCCAPTURE");
655 case VisibilityUnobscured
:
657 if (tfd
&& (ntfb_status
!= SETOFF
) && !fmode
) {
658 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
659 perror("ioctl VIDIOCCAPTURE");
667 if ((Event
.xany
.window
== fmwin
) && fmode
) {
668 switch(XKeycodeToKeysym(display
, Event
.xkey
.keycode
, 0)) {
670 if (isource
== TELEVISION
)
674 if (isource
== TELEVISION
)
709 /* ButtonDown function */
711 ButtonDown(int button
)
715 copyXPMArea(79, 100, 12, 11, 47, 48);
716 RedrawWindowXYWH (47, 48, 12, 11);
719 copyXPMArea(55, 100, 12, 11, 23, 48);
720 RedrawWindowXYWH(35, 48, 12, 11);
723 copyXPMArea(67, 100, 12, 11, 35, 48);
724 RedrawWindowXYWH(35, 48, 12, 11);
732 /* ButtonUp function */
738 copyXPMArea(79, 88, 12, 11, 47, 48);
739 RedrawWindowXYWH(47, 48, 12, 11);
742 copyXPMArea(55, 88, 12, 11, 23, 48);
743 RedrawWindowXYWH(23, 48, 12, 11);
746 copyXPMArea(67, 88, 12, 11, 35, 48);
747 RedrawWindowXYWH(35, 48, 12, 11);
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");
784 default: /* non-zero return */
785 fprintf(stderr
,"v4l-conf had some trouble, "
786 "trying to continue anyway\n");
788 /* End of "stolen" part */
801 vclip
[0].x
= 0; /* Clipping Rect 1 */
804 vclip
[0].height
= 39;
805 vclip
[1].x
= 59; /* Clipping Rect 2 */
808 vclip
[1].height
= 39;
813 vchn
.channel
= tvsource
;
814 vaud
.audio
= tvsource
;
819 isource
= TELEVISION
;
820 else if (*p
== 'C') {
824 compchannel
= atoi(p
);
831 if (ioctl(tfd
, VIDIOCGTUNER
, &vtun
) < 0)
832 perror("ioctl VIDIOCGTUNER");
833 if (vtun
.flags
& VIDEO_TUNER_LOW
)
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
];
860 DrawPresetChan(cchannel
);
862 else if (isource
== COMPOSITE
) {
863 DrawPresetChan(compchannel
);
865 else if (isource
== SVIDEO
) {
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");
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");
897 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0)
898 perror("ioctl VIDIOCCAPTURE");
900 vaud
.audio
= tvsource
;
902 vaud
.flags
|= VIDEO_AUDIO_MUTE
;
904 if (vchn
.flags
& VIDEO_VC_AUDIO
) {
905 if (ioctl(tfd
, VIDIOCSAUDIO
, &vaud
) < 0)
906 perror("ioctl VIDIOCSAUDIO");
910 copyXPMArea(66, 79, 11, 7, 6, 50);
911 RedrawWindowXYWH(6, 50, 11, 7);
915 /* VolumeUp function */
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 */
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 */
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");
963 /* UnMuteAudio function */
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");
978 /* ScanUp function */
984 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
985 perror("ioctl VIDIOCSFREQ");
989 if (ioctl(tfd
, VIDIOCGTUNER
, &vtun
) < 0) {
990 perror("ioctl VIDIOCGTUNER");
992 if (vtun
.signal
== 0xFFFF) {
999 /* ScanDown function */
1005 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
1006 perror("ioctl VIDIOCSFREQ");
1010 if (ioctl(tfd
, VIDIOCGTUNER
, &vtun
) < 0) {
1011 perror("ioctl VIDIOCGTUNER");
1013 if (vtun
.signal
== 0xFFFF) {
1019 /* FineTuneUp function */
1024 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
1025 perror("ioctl VIDIOCSFREQ");
1030 /* FineTuneDown function */
1035 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0) {
1036 perror("ioctl VIDIOCSFREQ");
1041 /* ChanUp function */
1046 if (cchannel
< maxpst
)
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
];
1056 DrawPresetChan(cchannel
);
1057 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0)
1058 perror("ioctl VIDIOCSFREQ");
1062 /* ChanDown function */
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
];
1077 DrawPresetChan(cchannel
);
1078 if (ioctl(tfd
, VIDIOCSFREQ
, &rfreq
) < 0)
1079 perror("ioctl VIDIOCSFREQ");
1083 /* DrawPresetChan function */
1085 DrawPresetChan(int cchannel
)
1092 if (isource
== TELEVISION
) {
1093 sprintf(temp
, "%02d", cchannel
+1);
1096 copyXPMArea(66, 79, 5, 7, k
, 50);
1102 copyXPMArea((*p
-'0')*6 + 1, 79, 5, 7, k
, 50);
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 */
1124 ParseRCFile(const char *filename
, rckeys
*keys
)
1128 char *tokens
= " =\t\n";
1132 if ((fp
= fopen(filename
, "r")) == NULL
) {
1133 fprintf(stderr
, "wmtv: %s\n", strerror(errno
));
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
);
1155 /* ParseRCFile2 function */
1157 ParseRCFile2(const char *filename
)
1160 char temp
[128], name
[128];
1164 if ((fp
= fopen(filename
, "r")) == NULL
) {
1165 fprintf(stderr
, "wmtv: %s\n", strerror(errno
));
1170 while (fgets(temp
, 128, fp
)) {
1171 if (*temp
!= '\n') {
1174 if(sscanf(temp
, " %s %n(%ld) %n", name
, &len
, &ftune
[i
], &len
)>=1) {
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
++) {
1189 else if (strchr(temp
, '[')) {
1199 /* WriteRCFile function */
1201 WriteRCFile(const char *filename
, rckeys
*keys
)
1207 if ((fp
= fopen(filename
, "w")) == NULL
) {
1208 fprintf(stderr
, "wmtv: %s\n", strerror(errno
));
1212 for (key
=0; keys
[key
].label
; key
++)
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
]);
1225 /* InitPalette function */
1229 if (ioctl(tfd
, VIDIOCGFBUF
, &vfb
) < 0) {
1230 perror ("ioctl VIDIOCGFBUF");
1233 if (vfb
.base
== NULL
) {
1234 fprintf(stderr
, "wmtv: no physical frame buffer access\n");
1239 if (ioctl(tfd
, VIDIOCGPICT
, &vpic
) < 0) {
1240 perror("ioctl VIDIOCGPICT");
1242 vpic
.depth
= vfb
.depth
;
1243 switch(vpic
.depth
) {
1245 vpic
.palette
= VIDEO_PALETTE_HI240
;
1248 vpic
.palette
= VIDEO_PALETTE_RGB555
;
1251 vpic
.palette
= VIDEO_PALETTE_RGB565
;
1254 vpic
.palette
= VIDEO_PALETTE_RGB24
;
1257 vpic
.palette
= VIDEO_PALETTE_RGB32
;
1260 fprintf(stderr
, "wmtv: unsupported depth %d\n", vpic
.depth
);
1263 if (ioctl(tfd
, VIDIOCSPICT
, &vpic
) < 0) {
1264 perror("ioctl VIDIOCSPICT");
1267 /* InitConfig function */
1273 ParseRCFile(usrConfFile
, wmtv_keys
);
1274 ParseRCFile2(usrConfFile
);
1277 ParseRCFile(sysConfFile
, wmtv_keys
);
1278 ParseRCFile2(sysConfFile
);
1281 fprintf(stderr
, "wmtv: error - config file not found\n");
1286 if (maxpreset
!= NULL
)
1287 maxpst
= atoi(maxpreset
) - 1;
1291 if ((tpst
) != atoi(maxpreset
)) {
1292 fprintf(stderr
, "wmtv: error - maxpreset value does not match total channel value\n");
1295 if ((tfd
= open(dev
, O_RDWR
)) < 0) {
1296 perror("open failed");
1298 card_present
= TRUE
;
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");
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
);
1320 if (!(vcap
.type
& VID_TYPE_CLIPPING
)) {
1321 fprintf(stderr
, "%s: video device does not support clipping\n", progname
);
1325 fswidth
= atoi(strtok(fullscreen
, "x\n"));
1326 fsheight
= atoi(strtok(NULL
, "x\n"));
1334 for (i
=0; i
< vcap
.channels
; i
++) {
1336 if (ioctl(tfd
, VIDIOCGCHAN
, &vchn
) < 0) {
1337 perror("ioctl VIDIOCGCHAN");
1339 if (!strcmp(vchn
.name
, source
)) {
1346 tvsource
= vchn
.channel
;
1348 if ((ioctl(tfd
, VIDIOCSCHAN
, &vchn
)) < 0)
1349 perror("ioctl VIDIOCSCHAN");
1353 fprintf(stderr
, "wmtv: invalid source in config file\n");
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
++) {
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 */
1410 GetFrameBuffer(void)
1413 void *baseaddr
= NULL
;
1414 int evbr
, erbr
, flr
= 0;
1415 int bankr
, memr
, depth
;
1417 int bytesperline
, bitsperpixel
;
1418 XPixmapFormatValues
*pf
;
1421 if (!XGetWindowAttributes(display
, DefaultRootWindow(display
), &Winattr
)) {
1422 fprintf(stderr
, "wmtv: error getting winattr of root\n");
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
);
1436 fprintf(stderr
, "wmtv: error - XF86DGA Extensions not available\n");
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
;
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)
1461 if (ioctl(tfd
, VIDIOCSFBUF
, &vfb
) < 0) {
1462 perror("ioctl VIDIOCSFBUF");
1468 /* DoFullScreen function */
1475 unsigned long back_pix
, fore_pix
;
1476 unsigned int borderwidth
= 0;
1479 XSizeHints fmsizehints
;
1480 XWMHints fmxwmhints
;
1483 unsigned long valuemask
;
1485 XSetWindowAttributes fmWinattr
;
1486 XWindowAttributes fmwinattr
;
1490 if (ioctl (tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
1491 perror("ioctl VIDIOCCAPTURE");
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
);
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
)) {
1538 fprintf(stderr
, "wmtv: xf86mode extension not present\n");
1539 fprintf(stderr
, " switch disabled\n");
1543 XMapWindow(display
, fmwin
);
1546 if (!XGetWindowAttributes(display
, fmwin
, &fmwinattr
)) {
1547 fprintf(stderr
, "wmtv: error getting winattr of fmwin\n");
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");
1569 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
1570 perror("ioctl VIDIOCCAPTURE");
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
;
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
);
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 */
1608 XF86VidModeModeInfo
*scm
= NULL
;
1611 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
)) {
1612 perror("ioctl VIDIOCCAPTURE");
1616 for (i
= 0; i
< tml
; i
++) {
1617 if ((modelines
[i
]->hdisplay
== Winattr
.width
) &&
1618 (modelines
[i
]->vdisplay
==Winattr
.height
))
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
);
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
);
1655 mode_present
= FALSE
;
1658 if (ioctl(tfd
, VIDIOCSWIN
, &vwin
) < 0) {
1659 perror("ioctl VIDIOCSWIN");
1662 if (ioctl(tfd
, VIDIOCCAPTURE
, &ccapt
) < 0) {
1663 perror("ioctl VIDIOCCAPTURE");
1668 /* GrabImage function */
1674 /* Usage function */
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 */
1696 fprintf(stderr
, "wmtv version %s\n", VERSION
);