Remove trailing whitespace.
[dockapps.git] / wmtv / src / wmtv.c
blob086e40bf686a5b8f41fe104f3af101dcbf668404
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 <sys/ioctl.h>
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <linux/videodev.h>
37 #include <linux/soundcard.h>
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xmd.h>
42 #include <X11/StringDefs.h>
43 #include <X11/keysym.h>
44 #include <X11/xpm.h>
45 #include <X11/extensions/shape.h>
46 #include <X11/extensions/xf86dga.h>
47 #include <X11/extensions/xf86vmode.h>
49 #include "wmgeneral/wmgeneral.h"
50 #include "wmgeneral/misc.h"
51 #include "wmtv-master.xpm"
52 #include "channels.h"
55 /* Defines */
56 #define VERSION "0.6.5"
58 #define ON 1
59 #define OFF 0
61 #define NTFB 0 /* On/SetTune/Off Button */
62 #define SCANLB 1 /* Scan Left Button */
63 #define SCANRB 2 /* Scan Right Button */
64 #define FULLSB 3 /* Full Screen Toggle Button */
66 #ifndef TRUE
67 #define TRUE 1
68 #endif
69 #ifndef FALSE
70 #define FALSE 0
71 #endif
73 #define SETON 0
74 #define SETOFF 1
75 #define SETUNE 2
76 #define SETSPD 3
78 #define MAXCHAN 100
79 #define OPTIONS "hvd:g:e:b:"
81 #define TELEVISION 0
82 #define COMPOSITE 1
83 #define SVIDEO 2
86 /* Global Variables */
87 int tfd;
88 int card_present = FALSE;
89 int ntfb_status = SETOFF;
90 char *maxpreset = NULL;
91 char **chan = NULL;
92 int mode_present = FALSE;
94 int chn = 0;
95 int aud = 0;
96 int tpst = 0;
97 int cchannel = 0;
98 int timebutton = 0;
99 int tvsource = 0;
100 int ccapt;
101 int norcfile = 0;
102 int ic = 0;
103 int cnotune = 0;
104 int vsource = 0;
105 int isource = 0;
106 int compchannel = 0;
107 int vidmode = 0;
108 int fmode = 0;
109 int mute = 0;
110 int dcret;
111 int tml;
112 int fswidth = 0;
113 int fsheight = 0;
115 unsigned long ccrfreq;
116 unsigned long rfreq;
117 unsigned long st;
118 unsigned long offset;
120 char *norm = NULL;
121 char *source;
122 char *mode = NULL;
123 char *fullscreen = NULL;
124 int freqnorm = -1;
125 char *cname[MAXCHAN];
126 char *wcname[MAXCHAN];
127 int ftune[MAXCHAN];
128 char *progname;
129 char *dev = "/dev/video";
131 int wmtv_mask_width = 64;
132 int wmtv_mask_height = 64;
133 char wmtv_mask_bits[64*64];
135 int btime = 0;
136 int but_pressed = FALSE;
137 int but_clicked = FALSE;
138 int maxpst;
139 int x_lc;
140 int y_lc;
141 Time t_lc;
143 rckeys wmtv_keys[] = {
144 { "freqnorm", &norm },
145 { "source", &source },
146 { "maxpreset", &maxpreset },
147 { "mode", &mode },
148 { "fullscreen", &fullscreen },
149 { NULL, NULL }
152 XEvent Event;
153 XWindowAttributes Winattr;
154 Window fmwin;
155 GC fmGC;
156 XF86VidModeModeInfo **modelines, *fullscreenmode = NULL;
157 XF86VidModeModeLine scmode;
159 struct video_capability vcap;
160 struct video_buffer vfb;
161 struct video_window vwin;
162 struct video_window vswin;
163 struct video_channel vchn, vchns;
164 struct video_picture vpic;
165 struct video_tuner vtun;
166 struct video_audio vaud;
167 struct video_mbuf vmbuf;
168 struct video_mmap vmmap;
169 struct video_clip vclip[2];
170 struct video_clip vclip2[2];
173 /* Function prototypes */
174 void TVOn(void);
175 void TVOff(void);
176 void TuneTV(void);
177 void ChanUp(void);
178 void ChanDown(void);
179 void FineTuneUp(void);
180 void FineTuneDown(void);
181 void ScanUp(void);
182 void ScanDown(void);
184 void ButtonUp(int);
185 void ButtonDown(int);
186 void Capture(void);
187 void MuteAudio(void);
188 void UnMuteAudio(void);
189 void VolumeUp(void);
190 void VolumeDown(void);
191 void DrawPresetChan(int);
192 void DoFullScreen(void);
193 void GetFrameBuffer(void);
194 void RetScreen(void);
195 void GrabImage(void);
197 void ParseRCFile(const char *, rckeys *);
198 void ParseRCFile2(const char *);
199 void WriteRCFile(const char *);
200 void InitConfig(void);
201 void InitPalette(void);
203 void Usage(void);
204 void Version(void);
207 /* main function */
209 main(int argc, char *argv[])
211 int i, c, opind;
212 // pid_t pid;
213 char cfile[128];
214 static struct option long_options[] = {
215 {"display", 1, 0, 'd'},
216 {"geometry", 1, 0, 'g'},
217 {"bpp", 1, 0, 'b'},
218 {"exe", 1, 0, 'e'},
219 {"help", 0, 0, 'h'},
220 {"version", 0, 0, 'v'},
221 {0, 0, 0, 0}
224 progname = strdup(argv[0]);
226 strncpy(cfile, (char *)getenv("HOME"), sizeof(char)*128);
227 strcat(cfile, "/.wmtvrc");
229 while (1) {
230 opind = 0;
231 c = getopt_long (argc, argv, OPTIONS, long_options, &opind);
232 if (c == -1)
233 break;
235 switch(c)
237 case 0:
239 fprintf(stderr, "wmtv: option - %s", long_options[opind].name);
240 if (optarg)
241 fprintf(stderr, " with arg %s", optarg);
242 printf("\n");
244 break;
245 case 'd':
246 display_name = strdup(optarg);
247 break;
248 case 'g':
249 geometry = strdup(optarg);
250 break;
251 case 'e':
252 exe = strdup(optarg);
253 strcat(exe, " &");
254 break;
255 case 'b':
256 fprintf(stderr, "wmtv: option not implemented yet\n");
257 Usage();
258 exit(1);
259 break;
260 case 'v':
261 Version();
262 exit(0);
263 break;
264 default:
265 Usage();
266 exit(1);
270 /* creat windows */
271 createXBMfromXPM (wmtv_mask_bits, wmtv_master_xpm,
272 wmtv_mask_width, wmtv_mask_height);
273 openXwindow (argc, argv, wmtv_master_xpm, wmtv_mask_bits,
274 wmtv_mask_width, wmtv_mask_height);
276 AddMouseRegion (NTFB, 47, 48, 59, 59); /* On/SetTune/Off Button */
277 AddMouseRegion (SCANLB, 23, 48, 35, 59); /* Left Preset/Scan Button */
278 AddMouseRegion (SCANRB, 35, 48, 47, 59); /* Right Preset/Scan Button */
279 AddMouseRegion (FULLSB, 5, 5, 59, 44); /* Toggle FullScreen */
281 /* wmtv main loop */
282 while (1)
284 while (XPending(display))
286 XNextEvent(display, &Event);
287 switch (Event.type) {
288 case Expose:
289 RedrawWindow();
290 break;
291 case DestroyNotify:
292 XCloseDisplay(display);
293 ccapt = 0;
294 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
295 perror("ioctl VIDIOCCAPTURE");
297 close(tfd);
298 usleep(50000L);
299 exit(0);
300 break;
301 case ButtonPress:
302 if ((Event.xany.window == fmwin) && fmode) {
303 RetScreen();
305 else {
306 i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
307 switch (i) {
308 case NTFB:
309 ButtonDown(NTFB);
310 t_lc = Event.xbutton.time;
311 but_pressed = TRUE;
312 break;
313 case SCANLB:
314 ButtonDown(SCANLB);
315 if (ntfb_status == SETUNE) {
316 switch (Event.xbutton.button) {
317 case 1:
318 timebutton = 1;
319 while (timebutton == 1)
320 if (isource == TELEVISION)
321 ScanDown();
322 break;
323 case 3:
324 if (isource == TELEVISION)
325 FineTuneDown();
326 break;
329 else
330 ChanDown();
331 break;
332 case SCANRB:
333 ButtonDown(SCANRB);
334 if (ntfb_status == SETUNE) {
335 switch (Event.xbutton.button) {
336 case 1:
337 timebutton = 1;
338 while (timebutton)
339 if (isource == TELEVISION)
340 ScanUp();
341 break;
342 case 3:
343 if (isource == TELEVISION)
344 FineTuneUp();
345 break;
348 else
349 ChanUp();
350 break;
351 case FULLSB:
352 ButtonDown(FULLSB);
353 switch (Event.xbutton.button) {
354 case 1:
355 but_pressed = TRUE;
356 break;
357 case 2:
358 but_pressed = TRUE;
359 break;
360 case 3:
361 if (!mute) {
362 MuteAudio();
364 else {
365 UnMuteAudio();
367 break;
369 break;
371 RedrawWindow();
373 break;
374 case ButtonRelease:
375 i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
376 switch (i) {
377 case NTFB:
378 ButtonUp(NTFB);
379 if (but_pressed) {
380 if (Event.xbutton.time - t_lc >= 900) {
381 btime = TRUE;
382 but_pressed = FALSE;
386 if (ntfb_status == SETOFF) {
387 ntfb_status = SETON;
388 TVOn();
390 else if (ntfb_status == SETON) {
391 if (!btime) {
392 ntfb_status = SETUNE;
393 copyXPMArea(96, 79, 11, 7, 6, 50);
394 RedrawWindowXYWH(6, 50, 11, 7);
396 else if (btime) {
397 ntfb_status = SETOFF;
398 btime = FALSE;
399 ic = TRUE;
400 TVOff();
403 else if (ntfb_status == SETUNE) {
404 if (!btime) {
405 offset = (rfreq - ccrfreq);
406 // fprintf(stderr, "wmtv: finetune offset = %ld\n", offset);
407 WriteRCFile(cfile);
408 ntfb_status = SETON;
409 DrawPresetChan(cchannel);
411 else if (btime) {
412 ntfb_status = SETOFF;
413 btime = FALSE;
414 ic = TRUE;
415 TVOff();
418 break;
419 case SCANLB:
420 ButtonUp(SCANLB);
421 if (ntfb_status == SETUNE)
422 timebutton = 0;
423 break;
424 case SCANRB:
425 ButtonUp(SCANRB);
426 if (ntfb_status == SETUNE)
427 timebutton = 0;
428 break;
429 case FULLSB:
430 ButtonUp(FULLSB);
431 switch (Event.xbutton.button) {
432 case 1: {
433 if (but_clicked) {
434 but_pressed = FALSE;
435 but_clicked = FALSE;
437 if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
439 if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
440 if (exe) {
441 ntfb_status = SETOFF;
442 TVOff();
443 system(exe);
445 pid = fork();
447 // child
448 if (pid == (pid_t) 0) {
449 execlp("xawtv", "xawtv", "&", (char *) 0);
452 else if (pid < (pid_t) 0) {
453 perror("fork");
456 // parent
457 else {
458 if (waitpid(pid, NULL, 0) < 0) {
459 perror("waitpid");
462 else {
463 DoFullScreen();
469 if (but_pressed) {
470 t_lc = Event.xbutton.time;
471 x_lc = Event.xbutton.x;
472 y_lc = Event.xbutton.y;
473 but_clicked = TRUE;
474 but_pressed = FALSE;
477 break;
478 case 2: {
479 if (but_clicked) {
480 but_pressed = FALSE;
481 but_clicked = FALSE;
483 if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
485 if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
486 DoFullScreen();
491 if (but_pressed) {
492 t_lc = Event.xbutton.time;
493 x_lc = Event.xbutton.x;
494 y_lc = Event.xbutton.y;
495 but_clicked = TRUE;
496 but_pressed = FALSE;
499 break;
500 case 3:
501 break;
503 break;
505 RedrawWindow();
506 break;
507 case VisibilityNotify:
508 switch(Event.xvisibility.state) {
509 case VisibilityFullyObscured:
510 ccapt = 0;
511 if (tfd && (ntfb_status != SETOFF) && !fmode) {
512 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
513 perror("ioctl VIDIOCCAPTURE");
516 break;
517 case VisibilityPartiallyObscured:
518 ccapt = 0;
519 if (tfd && (ntfb_status != SETOFF) && !fmode) {
520 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
521 perror("ioctl VIDIOCCAPTURE");
524 break;
525 case VisibilityUnobscured:
526 ccapt = 1;
527 if (tfd && (ntfb_status != SETOFF) && !fmode) {
528 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
529 perror("ioctl VIDIOCCAPTURE");
532 break;
534 RedrawWindow();
535 break;
536 case KeyPress:
537 if ((Event.xany.window == fmwin) && fmode) {
538 switch(XKeycodeToKeysym(display, Event.xkey.keycode, 0)) {
539 case XK_Up:
540 if (isource == TELEVISION)
541 ChanUp();
542 break;
543 case XK_Down:
544 if (isource == TELEVISION)
545 ChanDown();
546 break;
547 case XK_Right:
548 if (isource == TELEVISION)
549 FineTuneUp();
550 break;
551 case XK_Left:
552 if (isource == TELEVISION)
553 FineTuneDown();
554 break;
555 case XK_m:
556 if (!mute) {
557 MuteAudio();
559 else {
560 UnMuteAudio();
562 break;
563 case XK_Escape:
564 RetScreen();
565 break;
566 default:
567 break;
570 default:
571 break;
573 XFlush(display);
575 usleep(50000L);
577 return(0);
581 /* ButtonDown function */
582 void
583 ButtonDown(int button)
585 switch (button) {
586 case NTFB:
587 copyXPMArea(79, 100, 12, 11, 47, 48);
588 RedrawWindowXYWH (47, 48, 12, 11);
589 break;
590 case SCANLB:
591 copyXPMArea(55, 100, 12, 11, 23, 48);
592 RedrawWindowXYWH(35, 48, 12, 11);
593 break;
594 case SCANRB:
595 copyXPMArea(67, 100, 12, 11, 35, 48);
596 RedrawWindowXYWH(35, 48, 12, 11);
597 break;
598 case FULLSB:
599 break;
604 /* ButtonUp function */
605 void
606 ButtonUp(int button)
608 switch (button) {
609 case NTFB:
610 copyXPMArea(79, 88, 12, 11, 47, 48);
611 RedrawWindowXYWH(47, 48, 12, 11);
612 break;
613 case SCANLB:
614 copyXPMArea(55, 88, 12, 11, 23, 48);
615 RedrawWindowXYWH(23, 48, 12, 11);
616 break;
617 case SCANRB:
618 copyXPMArea(67, 88, 12, 11, 35, 48);
619 RedrawWindowXYWH(35, 48, 12, 11);
620 break;
621 case FULLSB:
622 break;
627 /* TVOn function */
628 void
629 TVOn(void)
631 int i;
632 Window junkwin;
633 int rx, ry;
634 char *p;
637 XWindowAttributes winattr;
639 if (!XGetWindowAttributes (display, iconwin, &winattr)) {
640 fprintf(stderr, "wmtv: error getting winattr of iconwin\n");
643 if (!XTranslateCoordinates(display, iconwin, winattr.root,
644 -winattr.border_width,
645 -winattr.border_width,
646 &rx, &ry, &junkwin)) {
647 fprintf(stderr, "wmtv: error translating coordinates\n");
650 InitConfig();
651 GetFrameBuffer();
652 InitPalette();
654 ccapt = 1;
656 vwin.x = rx;
657 vwin.y = ry + 5;
659 vwin.width = 64;
660 vwin.height = 39;
662 vclip[0].x = 0; /* Clipping Rect 1 */
663 vclip[0].y = 0;
664 vclip[0].width = 5;
665 vclip[0].height = 39;
666 vclip[1].x = 59; /* Clipping Rect 2 */
667 vclip[1].y = 0;
668 vclip[1].width = 5;
669 vclip[1].height = 39;
671 vwin.clips = vclip;
672 vwin.clipcount = 2;
674 vchn.channel = tvsource;
675 vaud.audio = tvsource;
677 if (source) {
678 p = source;
679 if (*p == 'T')
680 isource = TELEVISION;
681 else if (*p == 'C') {
682 isource = COMPOSITE;
683 while (isalpha(*p))
684 ++p;
685 compchannel = atoi(p);
687 else if (*p == 'S')
688 isource = SVIDEO;
691 if (!cnotune) {
692 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0)
693 perror("ioctl VIDIOCGTUNER");
694 if (vtun.flags & VIDEO_TUNER_LOW)
695 st = 16000;
696 else
697 st = 16;
700 if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0)
701 perror("ioctl VIDIOCGCHAN");
703 if (vchn.flags & VIDEO_VC_AUDIO) {
704 if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0)
705 perror("ioctl VIDIOCGAUDIO");
708 if (vaud.flags & VIDEO_AUDIO_MUTE) {
709 vaud.flags &= ~VIDEO_AUDIO_MUTE; /* Unmute */
710 vaud.volume = (0xFFFF/2)+1;
713 if (isource == TELEVISION) {
714 for (i=0; i < CHAN_ENTRIES; i++) {
715 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
716 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
717 ccrfreq = rfreq - ftune[cchannel];
718 break;
721 DrawPresetChan(cchannel);
723 else if (isource == COMPOSITE) {
724 DrawPresetChan(compchannel);
726 else if (isource == SVIDEO) {
727 DrawPresetChan(-1);
730 if (vchn.flags & VIDEO_VC_AUDIO) {
731 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
732 perror("ioctl VIDIOCSAUDIO");
736 if (ioctl(tfd, VIDIOCSCHAN, &vchn) < 0)
737 perror("ioctl VIDIOCSCHAN");
739 if (!cnotune) {
740 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
741 perror("ioctl VIDIOCSFREQ");
744 if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0)
745 perror("ioctl VIDIOCSWIN");
747 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
748 perror("ioctl VIDIOCCAPTURE");
752 /* TVOff function */
753 void
754 TVOff(void)
756 ccapt = 0;
758 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
759 perror("ioctl VIDIOCCAPTURE");
761 vaud.audio = tvsource;
762 vaud.volume = 0;
763 vaud.flags |= VIDEO_AUDIO_MUTE;
765 if (vchn.flags & VIDEO_VC_AUDIO) {
766 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
767 perror("ioctl VIDIOCSAUDIO");
770 close(tfd);
771 copyXPMArea(66, 79, 11, 7, 6, 50);
772 RedrawWindowXYWH(6, 50, 11, 7);
776 /* VolumeUp function */
777 void
778 VolumeUp(void)
780 if(vchn.flags & VIDEO_VC_AUDIO) {
781 if (vaud.volume <= 0xFFFF) {
782 vaud.audio = tvsource;
783 vaud.volume += (0xFFFF/10);
784 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
785 perror("ioctl VIDIOCSAUDIO");
791 /* VoumeDown function */
792 void
793 VolumeDown(void)
795 if (vchn.flags & VIDEO_VC_AUDIO) {
796 if (vaud.volume > 0) {
797 vaud.audio = tvsource;
798 vaud.volume -= (0xFFFF/10);
799 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
800 perror("ioctl VIDIOCSAUDIO");
805 /* MuteAudio function */
806 void
807 MuteAudio(void)
809 if (vchn.flags & VIDEO_VC_AUDIO) {
810 vaud.audio = tvsource;
811 // vaud.volume = 0;
812 vaud.flags |= VIDEO_AUDIO_MUTE;
813 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
814 perror("ioctl VIDIOCSAUDIO");
816 mute = TRUE;
820 /* UnMuteAudio function */
821 void
822 UnMuteAudio(void)
824 if ((vchn.flags & VIDEO_VC_AUDIO) && (vaud.flags & VIDEO_AUDIO_MUTE)) {
825 vaud.audio = tvsource;
826 // vaud.volume = (0xFFFF/2)+1;
827 vaud.flags &= ~VIDEO_AUDIO_MUTE;
828 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
829 perror("ioctl VIDIOCSAUDIO");
831 mute = FALSE;
835 /* ScanUp function */
836 void
837 ScanUp(void)
839 rfreq += 2;
840 usleep(50000L);
841 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
842 perror("ioctl VIDIOCSFREQ");
844 usleep(10000L);
845 vtun.tuner = 0;
846 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
847 perror("ioctl VIDIOCGTUNER");
849 if (vtun.signal == 0xFFFF) {
850 timebutton = 0;
856 /* ScanDown function */
857 void
858 ScanDown(void)
860 rfreq -= 2;
861 usleep(50000L);
862 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
863 perror("ioctl VIDIOCSFREQ");
865 usleep(10000L);
866 vtun.tuner = 0;
867 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
868 perror("ioctl VIDIOCGTUNER");
870 if (vtun.signal == 0xFFFF) {
871 timebutton = 0;
876 /* FineTuneUp function */
877 void
878 FineTuneUp(void)
880 rfreq += 1;
881 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
882 perror("ioctl VIDIOCSFREQ");
887 /* FineTuneDown function */
888 void
889 FineTuneDown(void)
891 rfreq -= 1;
892 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
893 perror("ioctl VIDIOCSFREQ");
898 /* ChanUp function */
899 void
900 ChanUp(void)
902 int i;
903 if (cchannel != maxpst)
904 ++cchannel;
905 for (i=0; i < CHAN_ENTRIES; i++) {
906 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
907 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
908 ccrfreq = rfreq - ftune[cchannel];
909 break;
913 DrawPresetChan(cchannel);
914 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
915 perror("ioctl VIDIOCSFREQ");
919 /* ChanDown function */
920 void
921 ChanDown(void)
923 int i;
924 if (cchannel != 0)
925 --cchannel;
926 for (i=0; i < CHAN_ENTRIES; i++) {
927 if (!strcmp(cname[cchannel], tvtuner[i].name)) {
928 rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
929 ccrfreq = rfreq - ftune[cchannel];
930 break;
934 DrawPresetChan(cchannel);
935 if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
936 perror("ioctl VIDIOCSFREQ");
940 /* DrawPresetChan function */
941 void
942 DrawPresetChan(int cchannel)
944 char temp[10];
945 char *p = temp;
946 int j=0;
947 int k=6;
949 if (isource == TELEVISION) {
950 sprintf(temp, "%02d", cchannel);
952 if (*p == '0') {
953 copyXPMArea(66, 79, 5, 7, k, 50);
954 k += 6;
955 j++;
956 p++;
958 while (j < 2) {
959 copyXPMArea((*p-'0')*6 + 1, 79, 5, 7, k, 50);
960 k += 6;
961 p++;
962 j++;
966 else if (isource == COMPOSITE) {
967 copyXPMArea (109, 79, 5, 7, 6, 50);
968 copyXPMArea ((compchannel*6) + 1, 79, 5, 7, 12, 50);
971 else if (isource == SVIDEO) {
972 copyXPMArea(116, 79, 11, 7, 6, 50);
975 RedrawWindowXYWH(6, 50, 11, 7);
979 /* ParseRCFile function */
980 void
981 ParseRCFile(const char *filename, rckeys *keys)
983 char *p,*q;
984 char temp[128];
985 char *tokens = " =\t\n";
986 FILE *fp;
987 int key = 0;
989 if ((fp = fopen(filename, "r")) == NULL) {
990 fprintf(stderr, "wmtv: %s\n", strerror(errno));
991 norcfile = 1;
992 return;
994 norcfile = 0;
995 while (fgets(temp, 128, fp)) {
996 key = 0;
997 q = strdup(temp);
998 if (*q != '\n') {
999 q = strtok(q, tokens);
1000 while (key >= 0 && keys[key].label) {
1001 if ((!strcmp(q, keys[key].label))) {
1002 p = strtok(NULL, tokens);
1003 free(*keys[key].var);
1004 *keys[key].var = strdup(p);
1005 key = -1;
1006 } else key++;
1009 free(q);
1011 fclose(fp);
1015 /* ParseRCFile2 function */
1016 void
1017 ParseRCFile2(const char *filename)
1019 int menu = FALSE;
1020 char temp[128];
1021 char tp[10];
1022 char *tokens = " \t\n()";
1023 char *q, *p;
1024 FILE *fp;
1025 int i = 0;
1027 if ((fp = fopen(filename, "r")) == NULL) {
1028 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1029 norcfile = 1;
1030 return;
1032 norcfile = 0;
1033 while (fgets(temp, 128, fp)) {
1034 q = strdup(temp);
1035 if (*q != '\n') {
1036 q = strtok(q, tokens);
1037 if (menu) {
1038 cname[i] = (char *)malloc(sizeof(q));
1039 strncpy(cname[i], q, sizeof(q));
1040 p = q;
1041 p = strtok(NULL, tokens);
1042 if (p != NULL) {
1043 if (*p == '-') {
1044 p++;
1045 ftune[i] = -1*atoi(p);
1047 else if (*p == '+') {
1048 p++;
1049 ftune[i] = atoi(p);
1051 else {
1052 ftune[i] = atoi(p);
1055 else {
1056 ftune[i] = 0;
1058 wcname[i] = (char *)malloc(sizeof(cname[i])+sizeof(p));
1059 wcname[i] = strdup(cname[i]);
1060 sprintf(tp, " (%d) ", ftune[i]);
1061 strcat(wcname[i], tp);
1062 i++;
1063 tpst = i;
1065 if ((q = strchr(q, '[')) != NULL) {
1066 menu = TRUE;
1070 fclose(fp);
1074 /* WriteRCFile function */
1075 void
1076 WriteRCFile(const char *filename)
1078 int i;
1079 char temp[128];
1080 char tp[10];
1081 char *tokens = " \t\n()";
1082 char *q;
1083 FILE *fp;
1085 if ((fp = fopen(filename, "r+")) == NULL) {
1086 fprintf(stderr, "wmtv: %s\n", strerror(errno));
1087 return;
1091 while (fgets(temp, 128, fp)) {
1092 q = strdup(temp);
1093 if (*q != '\n') {
1094 q = strtok(temp, tokens);
1095 if ((q = strchr(q, '[')) != NULL) {
1096 for (i = 0; i <= maxpst; i++) {
1097 // fprintf(stderr, "offset is %ld\n", offset);
1098 sprintf(tp, " (%ld) ", offset);
1099 strtok(wcname[cchannel], tokens);
1100 strcat(wcname[cchannel], tp);
1101 fputs(wcname[i], fp);
1102 fputs("\n", fp);
1107 fclose(fp);
1111 /* InitPalette function */
1112 void
1113 InitPalette(void)
1115 if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
1116 perror ("ioctl VIDIOCGFBUF");
1117 exit(-1);
1119 if (vfb.base == NULL) {
1120 fprintf(stderr, "wmtv: no physical frame buffer access\n");
1121 exit(1);
1125 if (ioctl(tfd, VIDIOCGPICT, &vpic) < 0) {
1126 perror("ioctl VIDIOCGPICT");
1128 vpic.depth = vfb.depth;
1129 switch(vpic.depth) {
1130 case 8:
1131 vpic.palette = VIDEO_PALETTE_HI240;
1132 break;
1133 case 15:
1134 vpic.palette = VIDEO_PALETTE_RGB555;
1135 break;
1136 case 16:
1137 vpic.palette = VIDEO_PALETTE_RGB565;
1138 break;
1139 case 24:
1140 vpic.palette = VIDEO_PALETTE_RGB24;
1141 break;
1142 case 32:
1143 vpic.palette = VIDEO_PALETTE_RGB32;
1144 break;
1145 default:
1146 fprintf(stderr, "wmtv: unsupported depth %d\n", vpic.depth);
1147 exit(-1);
1149 if (ioctl(tfd, VIDIOCSPICT, &vpic) < 0) {
1150 perror("ioctl VIDIOCSPICT");
1153 /* InitConfig function */
1154 void
1155 InitConfig(void)
1157 int i;
1158 char temp[128];
1160 strcpy(temp, "/etc/wmtvrc");
1161 ParseRCFile(temp, wmtv_keys);
1162 ParseRCFile2(temp);
1164 strncpy(temp, (char *)getenv("HOME"), (sizeof(char)*128));
1165 strcat(temp, "/.wmtvrc");
1166 ParseRCFile(temp, wmtv_keys);
1167 ParseRCFile2(temp);
1169 if (norcfile) {
1170 fprintf(stderr, "wmtv: error - config file not found\n");
1171 exit(1);
1174 if (maxpreset != NULL)
1175 maxpst = atoi(maxpreset) - 1;
1176 else
1177 maxpst = 1;
1179 if ((tpst) != atoi(maxpreset)) {
1180 fprintf(stderr, "wmtv: error - maxpreset value does not match total channel value\n");
1181 exit(1);
1183 if ((tfd = open(dev, O_RDWR)) < 0) {
1184 perror("open failed");
1186 card_present = TRUE;
1188 if (norm)
1189 for (i=0; i < CHAN_NAMES; i++) {
1190 if (!strcmp(chan_names[i].cname, norm)) {
1191 freqnorm = chan_names[i].cind;
1195 if (freqnorm == -1) {
1196 fprintf(stderr, "wmtv: error - set freqnorm in config file\n");
1197 exit(1);
1200 if (ioctl(tfd, VIDIOCGCAP, &vcap) < 0) {
1201 perror("ioctl VIDIOCGCAP");
1204 if (!(vcap.type & VID_TYPE_SCALES)) {
1205 fprintf(stderr, "%s: video device does not support scalling\n", progname);
1206 exit(1);
1208 if (!(vcap.type & VID_TYPE_CLIPPING)) {
1209 fprintf(stderr, "%s: video device does not support clipping\n", progname);
1212 if (fullscreen) {
1213 fswidth = atoi(strtok(fullscreen, "x\n"));
1214 fsheight = atoi(strtok(NULL, "x\n"));
1216 else {
1217 fswidth = 640;
1218 fsheight = 480;
1221 if (source) {
1222 for (i=0; i < vcap.channels; i++) {
1223 vchn.channel = i;
1224 if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0) {
1225 perror("ioctl VIDIOCGCHAN");
1227 if (!strcmp(vchn.name, source)) {
1228 if (vchn.tuners)
1229 cnotune = 0;
1230 else
1231 cnotune = 1;
1233 vsource = 1;
1234 tvsource = vchn.channel;
1236 if ((ioctl(tfd, VIDIOCSCHAN, &vchn)) < 0)
1237 perror("ioctl VIDIOCSCHAN");
1240 if (!vsource)
1241 fprintf(stderr, "wmtv: invalid source in config file\n");
1244 if (mode) {
1245 if (!cnotune) {
1246 vtun.tuner = 0;
1247 if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
1248 perror("ioctl VIDIOCGTUNER");
1251 if (!strcmp(mode, "pal")) {
1252 if (vtun.flags & VIDEO_TUNER_PAL) {
1253 vtun.mode = VIDEO_MODE_PAL;
1254 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1255 perror("ioctl VIDIOCSTUNER");
1259 if (!strcmp(mode, "ntsc")) {
1260 if (vtun.flags & VIDEO_TUNER_NTSC) {
1261 vtun.mode = VIDEO_MODE_NTSC;
1262 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1263 perror("ioctl VIDIOCSTUNER");
1267 if (!strcmp(mode, "secam")) {
1268 if (vtun.flags & VIDEO_TUNER_SECAM) {
1269 vtun.mode = VIDEO_MODE_SECAM;
1270 if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
1271 perror("ioctl VIDIOCSTUNER");
1278 for (i=0; i < vcap.audios; i++) {
1279 vaud.audio = i;
1280 if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0) {
1281 perror("ioctl VIDIOCGAUDIO");
1283 if (!(vaud.flags & VIDEO_AUDIO_MUTE)) {
1284 vaud.flags |= VIDEO_AUDIO_MUTE;
1285 if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) {
1286 perror("ioctl VIDIOCSAUDIO");
1291 if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
1292 perror("ioctl VIDIOCGFBUF");
1296 /* GetFrameBuffer function */
1297 void
1298 GetFrameBuffer(void)
1300 void *baseaddr = NULL;
1301 int evbr, erbr, flr = 0;
1302 int bankr, memr, depth;
1303 int i, n;
1304 int bytesperline, bitsperpixel;
1305 XPixmapFormatValues *pf;
1307 if (!XGetWindowAttributes(display, DefaultRootWindow(display), &Winattr)) {
1308 fprintf(stderr, "wmtv: error getting winattr of root\n");
1311 depth = Winattr.depth;
1313 if (XF86DGAQueryExtension(display, &evbr, &erbr)) {
1314 XF86DGAQueryDirectVideo(display, XDefaultScreen(display), &flr);
1315 if (flr & XF86DGADirectPresent) {
1316 XF86DGAGetVideoLL(display, XDefaultScreen(display),
1317 (int *) &baseaddr, &bytesperline, &bankr, &memr);
1320 else {
1321 fprintf(stderr, "wmtv: error - XF86DGA Extensions not available\n");
1322 exit(1);
1326 pf = XListPixmapFormats(display, &n);
1327 for (i=0; i < n; i++) {
1328 if (pf[i].depth == depth) {
1329 depth = pf[i].bits_per_pixel;
1330 break;
1334 bitsperpixel = (depth+7) & 0xf8; /* Taken from */
1335 bytesperline = Winattr.width * bitsperpixel / 8; /* Gerd Knorr's xawtv */
1337 vfb.base = baseaddr;
1338 vfb.height = Winattr.height;
1339 vfb.width = Winattr.width;
1340 vfb.depth = bitsperpixel;
1341 vfb.bytesperline = bytesperline;
1343 if (Winattr.depth == 15)
1344 vfb.depth = 15;
1346 if (ioctl(tfd, VIDIOCSFBUF, &vfb) < 0) {
1347 perror("ioctl VIDIOCSFBUF");
1352 /* DoFullScreen function */
1353 void
1354 DoFullScreen(void)
1356 int i;
1357 int evbr, erbr = 0;
1358 int rx, ry;
1359 unsigned long back_pix, fore_pix;
1360 unsigned int borderwidth = 0;
1362 Window junkwin;
1363 XSizeHints fmsizehints;
1364 XWMHints fmxwmhints;
1365 XGCValues gcv;
1366 unsigned long gcm;
1367 unsigned long valuemask;
1369 XSetWindowAttributes fmWinattr;
1370 XWindowAttributes fmwinattr;
1373 ccapt = 0;
1374 if (ioctl (tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1375 perror("ioctl VIDIOCCAPTURE");
1378 fmsizehints.x = 0;
1379 fmsizehints.y = 0;
1380 fmsizehints.width = fswidth;
1381 fmsizehints.height = fsheight;
1382 fmsizehints.max_width = vcap.maxwidth;
1383 fmsizehints.max_height = vcap.maxheight;
1384 fmsizehints.min_width = fswidth;
1385 fmsizehints.min_height = fsheight;
1386 fmsizehints.flags = (USPosition | USSize | PSize | PMinSize | PMaxSize);
1388 valuemask = 0;
1390 back_pix = WhitePixel(display, DefaultScreen(display));
1391 fore_pix = BlackPixel(display, DefaultScreen(display));
1393 fmwin = XCreateWindow(display, DefaultRootWindow(display), fmsizehints.x,
1394 fmsizehints.y, fmsizehints.width, fmsizehints.height,
1395 borderwidth, CopyFromParent, InputOutput,
1396 CopyFromParent, valuemask, &fmWinattr);
1399 XSetWMNormalHints(display, fmwin, &fmsizehints);
1401 gcm = (GCForeground | GCBackground | GCGraphicsExposures);
1402 gcv.foreground = fore_pix;
1403 gcv.background = back_pix;
1404 gcv.graphics_exposures = 0;
1406 fmGC = XCreateGC(display, DefaultRootWindow(display), gcm, &gcv);
1408 XSelectInput(display, fmwin, ButtonPressMask | ExposureMask |
1409 ButtonReleaseMask | PointerMotionMask |
1410 StructureNotifyMask | VisibilityChangeMask | KeyPressMask );
1412 fmxwmhints.flags = StateHint;
1413 fmxwmhints.initial_state = NormalState;
1415 XSetWMHints(display, fmwin, &fmxwmhints);
1418 if (XF86VidModeQueryExtension(display, &evbr, &erbr)) {
1419 vidmode = TRUE;
1421 else {
1422 fprintf(stderr, "wmtv: xf86mode extension not present\n");
1423 fprintf(stderr, " switch disabled\n");
1427 XMapWindow(display, fmwin);
1429 usleep(50000L);
1430 if (!XGetWindowAttributes(display, fmwin, &fmwinattr)) {
1431 fprintf(stderr, "wmtv: error getting winattr of fmwin\n");
1434 usleep(50000L);
1435 if (!XTranslateCoordinates(display, fmwin, DefaultRootWindow(display),
1436 -fmwinattr.border_width,
1437 -fmwinattr.border_width,
1438 &rx, &ry, &junkwin)) {
1439 fprintf(stderr, "wmtv: error translating coordinates for fmwin");
1442 vswin.width = fswidth;
1443 vswin.height = fsheight;
1444 vswin.x = fmsizehints.x + rx;
1445 vswin.y = fmsizehints.y + ry;
1446 vswin.clipcount = 0;
1448 if (ioctl(tfd, VIDIOCSWIN, &vswin) < 0) {
1449 perror("ioctl VIDIOCSWIN");
1452 ccapt = 1;
1453 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1454 perror("ioctl VIDIOCCAPTURE");
1456 fmode = TRUE;
1458 if (vidmode) {
1459 XF86VidModeGetModeLine(display, XDefaultScreen(display), &dcret, &scmode);
1460 XF86VidModeGetAllModeLines(display, XDefaultScreen(display), &tml, &modelines);
1462 for (i=0; i < tml; i++) {
1463 if ((modelines[i]->hdisplay == fswidth) &&
1464 (modelines[i]->vdisplay == fsheight)) {
1465 fullscreenmode = modelines[i];
1466 mode_present = TRUE;
1467 break;
1471 if (!mode_present) {
1472 fprintf(stderr, "wmtv: mode line for resolution %d x %d not found\n", vcap.maxwidth, vcap.maxheight);
1475 XRaiseWindow(display, fmwin);
1476 if (mode_present) {
1478 XF86VidModeSwitchToMode(display, XDefaultScreen(display), fullscreenmode);
1479 XF86VidModeSetViewPort(display, XDefaultScreen(display), vswin.x, vswin.y);
1480 XGrabPointer(display, fmwin, True, 0, GrabModeAsync, GrabModeAsync,
1481 fmwin, None, CurrentTime);
1487 /* RetScreen function */
1488 void
1489 RetScreen()
1491 int i;
1492 XF86VidModeModeInfo *scm = NULL;
1494 ccapt = 0;
1495 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt)) {
1496 perror("ioctl VIDIOCCAPTURE");
1499 if (mode_present) {
1500 for (i = 0; i < tml; i++) {
1501 if ((modelines[i]->hdisplay == Winattr.width) &&
1502 (modelines[i]->vdisplay==Winattr.height))
1503 scm = modelines[i];
1506 scm->dotclock = dcret;
1507 scm->hdisplay = scmode.hdisplay;
1508 scm->hsyncstart = scmode.hsyncstart;
1509 scm->hsyncend = scmode.hsyncend;
1510 scm->htotal = scmode.htotal;
1511 scm->vdisplay = scmode.vdisplay;
1512 scm->vsyncstart = scmode.vsyncstart;
1513 scm->vsyncend = scmode.vsyncend;
1514 scm->vtotal = scmode.vtotal;
1515 scm->flags = scmode.flags;
1517 scm->privsize = scmode.privsize;
1518 scm->private = scmode.private;
1521 XClearWindow(display, fmwin);
1522 XFreeGC(display, fmGC);
1523 XMapRaised(display, fmwin);
1524 XUnmapWindow(display, fmwin);
1525 XUngrabPointer(display, CurrentTime);
1527 else {
1528 XClearWindow(display, fmwin);
1529 XFreeGC(display, fmGC);
1530 XMapRaised(display, fmwin);
1531 XUnmapWindow(display, fmwin);
1534 if (vidmode && mode_present) {
1535 XF86VidModeSwitchToMode(display, XDefaultScreen(display), scm);
1536 vidmode = FALSE;
1538 fmode = FALSE;
1539 mode_present = FALSE;
1541 ccapt = 1;
1542 if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0) {
1543 perror("ioctl VIDIOCSWIN");
1546 if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
1547 perror("ioctl VIDIOCCAPTURE");
1549 RedrawWindow();
1552 /* GrabImage function */
1553 void
1554 GrabImage(void)
1558 /* Usage function */
1559 void
1560 Usage(void)
1562 fprintf(stderr, "\n");
1563 fprintf(stderr, "wmtv v%s, Copyright (c) 1999 Wee Liang <wliang@tartarus.uwa.edu.au>\n", VERSION);
1564 fprintf(stderr, "usage: wmtv [%s]\n", OPTIONS);
1565 fprintf(stderr, " -d, --display <host:vs>\tsets display name\n");
1566 fprintf(stderr, " -g, --geometry <{+-}XP{+-}YP>\tsets geometry\n");
1567 fprintf(stderr, " -b, --bpp\t\t\tdisplay color depth\n");
1568 fprintf(stderr, " -e, --exe <filename>\t\tprogram to execute\n");
1569 fprintf(stderr, " -v, --version\t\t\tprints version information\n");
1570 fprintf(stderr, " -h, --help\t\t\tprints this message\n");
1571 fprintf(stderr, "\n");
1575 /* Version function */
1576 void
1577 Version(void)
1579 fprintf(stderr, "wmtv version %s\n", VERSION);