1699 lines
36 KiB
C
1699 lines
36 KiB
C
/* Copyright (c) 1999 Wee Liang (wliang@tartarus.uwa.edu.au)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program (see the file COPYING); if not, write to the
|
|
* Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
|
|
/* Includes */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <getopt.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <libv4l1-videodev.h>
|
|
#include <linux/soundcard.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xmd.h>
|
|
#include <X11/StringDefs.h>
|
|
#include <X11/XKBlib.h>
|
|
#include <X11/xpm.h>
|
|
#include <X11/extensions/shape.h>
|
|
#include <X11/extensions/Xxf86dga.h>
|
|
#include <X11/extensions/xf86vmode.h>
|
|
|
|
#include "wmgeneral/wmgeneral.h"
|
|
#include "wmtv-master.xpm"
|
|
#include "channels.h"
|
|
|
|
|
|
/* Defines */
|
|
#define ON 1
|
|
#define OFF 0
|
|
|
|
#define NTFB 0 /* On/SetTune/Off Button */
|
|
#define SCANLB 1 /* Scan Left Button */
|
|
#define SCANRB 2 /* Scan Right Button */
|
|
#define FULLSB 3 /* Full Screen Toggle Button */
|
|
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#endif
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
|
|
#define SETON 0
|
|
#define SETOFF 1
|
|
#define SETUNE 2
|
|
#define SETSPD 3
|
|
|
|
#define MAXCHAN 99
|
|
#define OPTIONS "hvd:g:e:b:c:"
|
|
|
|
#define TELEVISION 0
|
|
#define COMPOSITE 1
|
|
#define SVIDEO 2
|
|
|
|
#ifndef GLOBALCONFFILE
|
|
#define GLOBALCONFFILE "/etc/wmtvrc"
|
|
#endif
|
|
|
|
/* Global Variables */
|
|
Display *display;
|
|
int tfd;
|
|
int card_present = FALSE;
|
|
int ntfb_status = SETOFF;
|
|
char *maxpreset = NULL;
|
|
char **chan = NULL;
|
|
int mode_present = FALSE;
|
|
|
|
int chn = 0;
|
|
int aud = 0;
|
|
int tpst = 0;
|
|
int cchannel = 0;
|
|
int timebutton = 0;
|
|
int tvsource = 0;
|
|
int ccapt;
|
|
int norcfile = 0;
|
|
int ic = 0;
|
|
int cnotune = 0;
|
|
int vsource = 0;
|
|
int isource = 0;
|
|
int compchannel = 0;
|
|
int vidmode = 0;
|
|
int fmode = 0;
|
|
int mute = 0;
|
|
int dcret;
|
|
int tml;
|
|
int fswidth = 0;
|
|
int fsheight = 0;
|
|
pid_t child_pid = -1;
|
|
int restart = FALSE;
|
|
|
|
unsigned long ccrfreq;
|
|
unsigned long rfreq;
|
|
unsigned long st;
|
|
|
|
char *norm = NULL;
|
|
char *source;
|
|
char *mode = NULL;
|
|
char *fullscreen = NULL;
|
|
int freqnorm = -1;
|
|
char *cname[MAXCHAN];
|
|
char *comment[MAXCHAN];
|
|
long ftune[MAXCHAN];
|
|
char *progname;
|
|
char *dev = "/dev/video";
|
|
|
|
char *sysConfFile = GLOBALCONFFILE;
|
|
char *usrConfFile;
|
|
|
|
int wmtv_mask_width = 64;
|
|
int wmtv_mask_height = 64;
|
|
char wmtv_mask_bits[64*64];
|
|
|
|
int btime = 0;
|
|
int but_pressed = FALSE;
|
|
int but_clicked = FALSE;
|
|
int maxpst;
|
|
int x_lc;
|
|
int y_lc;
|
|
Time t_lc;
|
|
|
|
rckeys wmtv_keys[] = {
|
|
{ "freqnorm", &norm },
|
|
{ "source", &source },
|
|
{ "maxpreset", &maxpreset },
|
|
{ "mode", &mode },
|
|
{ "fullscreen", &fullscreen },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
XEvent Event;
|
|
XWindowAttributes Winattr;
|
|
Window fmwin;
|
|
GC fmGC;
|
|
XF86VidModeModeInfo **modelines, *fullscreenmode = NULL;
|
|
XF86VidModeModeLine scmode;
|
|
|
|
struct video_capability vcap;
|
|
struct video_buffer vfb;
|
|
struct video_window vwin;
|
|
struct video_window vswin;
|
|
struct video_channel vchn, vchns;
|
|
struct video_picture vpic;
|
|
struct video_tuner vtun;
|
|
struct video_audio vaud;
|
|
struct video_mbuf vmbuf;
|
|
struct video_mmap vmmap;
|
|
struct video_clip vclip[2];
|
|
struct video_clip vclip2[2];
|
|
|
|
|
|
/* Function prototypes */
|
|
void TVOn(void);
|
|
void TVOff(void);
|
|
void TuneTV(void);
|
|
void ChanUp(void);
|
|
void ChanDown(void);
|
|
void FineTuneUp(void);
|
|
void FineTuneDown(void);
|
|
void ScanUp(void);
|
|
void ScanDown(void);
|
|
|
|
void ButtonUp(int);
|
|
void ButtonDown(int);
|
|
void Capture(void);
|
|
void MuteAudio(void);
|
|
void UnMuteAudio(void);
|
|
void VolumeUp(void);
|
|
void VolumeDown(void);
|
|
void DrawPresetChan(int);
|
|
void DoFullScreen(void);
|
|
void GetFrameBuffer(void);
|
|
void RetScreen(void);
|
|
void GrabImage(void);
|
|
|
|
void ParseRCFile(const char *, rckeys *);
|
|
void ParseRCFile2(const char *);
|
|
void WriteRCFile(const char *, rckeys *);
|
|
void InitConfig(void);
|
|
void InitPalette(void);
|
|
|
|
void Usage(void);
|
|
void Version(void);
|
|
|
|
void
|
|
sigchld_handler(int i)
|
|
{
|
|
pid_t pid;
|
|
pid = waitpid((pid_t)-1, NULL, WNOHANG);
|
|
while (pid>(pid_t)0) {
|
|
if (pid == child_pid) {
|
|
child_pid = -1;
|
|
restart = TRUE;
|
|
}
|
|
pid = waitpid((pid_t)-1, NULL, WNOHANG);
|
|
}
|
|
}
|
|
|
|
void
|
|
init_signal()
|
|
{
|
|
struct sigaction sa;
|
|
|
|
sa.sa_handler = &sigchld_handler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART;
|
|
sigaction(SIGCHLD, &sa, NULL);
|
|
}
|
|
|
|
char *
|
|
expand_format(char *format, char *letters, char **expansions)
|
|
{
|
|
char *string;
|
|
unsigned int string_pos = 0;
|
|
unsigned int size;
|
|
size = strlen(format)+1;
|
|
string = (char *)malloc(size*sizeof(char));
|
|
for (; *format != '\0'; format++) {
|
|
if (*format == '%') {
|
|
format++;
|
|
if (*format != '%') {
|
|
unsigned int i;
|
|
for (i = 0; letters[i] != '\0'; i++) {
|
|
if (letters[i] == *format)
|
|
break;
|
|
}
|
|
if (letters[i] != '\0') {
|
|
unsigned int expansion_size;
|
|
expansion_size = strlen(expansions[i]);
|
|
while (string_pos+expansion_size+1 > size) {
|
|
size *= 2;
|
|
string = realloc(string, size*sizeof(char));
|
|
}
|
|
memcpy(string+string_pos, expansions[i], expansion_size);
|
|
string_pos += expansion_size;
|
|
continue;
|
|
}
|
|
else {
|
|
format--;
|
|
}
|
|
}
|
|
}
|
|
while (string_pos+1+1 > size) {
|
|
size *= 2;
|
|
string = realloc(string, size*sizeof(char));
|
|
}
|
|
string[string_pos] = *format;
|
|
string_pos++;
|
|
}
|
|
string[string_pos] = '\0';
|
|
return string;
|
|
}
|
|
|
|
/* main function */
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int c, opind;
|
|
int pressed_button = -1;
|
|
/* pid_t pid; */
|
|
static struct option long_options[] = {
|
|
{"device", 1, 0, 'c'},
|
|
{"display", 1, 0, 'd'},
|
|
{"geometry", 1, 0, 'g'},
|
|
{"bpp", 1, 0, 'b'},
|
|
{"exe", 1, 0, 'e'},
|
|
{"help", 0, 0, 'h'},
|
|
{"version", 0, 0, 'v'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
progname = strdup(argv[0]);
|
|
|
|
{
|
|
char *home = getenv("HOME");
|
|
|
|
if (home == NULL) {
|
|
fprintf(stderr, "wmtv: $HOME should be set.\n");
|
|
exit(1);
|
|
}
|
|
|
|
usrConfFile = (char *)malloc(sizeof(char)*(strlen(home)+8+1));
|
|
strcpy(usrConfFile, home);
|
|
strcat(usrConfFile, "/.wmtvrc");
|
|
}
|
|
|
|
while (1) {
|
|
opind = 0;
|
|
c = getopt_long (argc, argv, OPTIONS, long_options, &opind);
|
|
if (c == -1)
|
|
break;
|
|
|
|
switch(c)
|
|
{
|
|
case 0:
|
|
/*
|
|
fprintf(stderr, "wmtv: option - %s", long_options[opind].name);
|
|
if (optarg)
|
|
fprintf(stderr, " with arg %s", optarg);
|
|
printf("\n");
|
|
*/
|
|
break;
|
|
case 'd':
|
|
display_name = strdup(optarg);
|
|
break;
|
|
case 'g':
|
|
geometry = strdup(optarg);
|
|
break;
|
|
case 'e':
|
|
exe = strdup(optarg);
|
|
/* strcat(exe, " &"); */
|
|
break;
|
|
case 'c':
|
|
dev = strdup(optarg);
|
|
break;
|
|
case 'b':
|
|
fprintf(stderr, "wmtv: option not implemented yet\n");
|
|
Usage();
|
|
exit(1);
|
|
break;
|
|
case 'v':
|
|
Version();
|
|
exit(0);
|
|
break;
|
|
default:
|
|
Usage();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* creat windows */
|
|
createXBMfromXPM (wmtv_mask_bits, wmtv_master_xpm,
|
|
wmtv_mask_width, wmtv_mask_height);
|
|
openXwindow (argc, argv, wmtv_master_xpm, wmtv_mask_bits,
|
|
wmtv_mask_width, wmtv_mask_height);
|
|
|
|
AddMouseRegion (NTFB, 47, 48, 59, 59); /* On/SetTune/Off Button */
|
|
AddMouseRegion (SCANLB, 23, 48, 35, 59); /* Left Preset/Scan Button */
|
|
AddMouseRegion (SCANRB, 35, 48, 47, 59); /* Right Preset/Scan Button */
|
|
AddMouseRegion (FULLSB, 5, 5, 59, 44); /* Toggle FullScreen */
|
|
|
|
init_signal();
|
|
|
|
/* wmtv main loop */
|
|
while (1)
|
|
{
|
|
if (restart) {
|
|
TVOn();
|
|
if (ntfb_status == SETOFF) {
|
|
ntfb_status = SETON;
|
|
RedrawWindow();
|
|
XFlush(display);
|
|
}
|
|
restart = FALSE;
|
|
continue;
|
|
}
|
|
while (XPending(display))
|
|
{
|
|
XNextEvent(display, &Event);
|
|
switch (Event.type) {
|
|
case Expose:
|
|
RedrawWindow();
|
|
break;
|
|
case DestroyNotify:
|
|
XCloseDisplay(display);
|
|
ccapt = 0;
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
close(tfd);
|
|
usleep(50000L);
|
|
exit(0);
|
|
break;
|
|
case ButtonPress:
|
|
if ((Event.xany.window == fmwin) && fmode) {
|
|
RetScreen();
|
|
}
|
|
else {
|
|
pressed_button = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
|
|
switch (pressed_button) {
|
|
case NTFB:
|
|
ButtonDown(NTFB);
|
|
t_lc = Event.xbutton.time;
|
|
but_pressed = TRUE;
|
|
break;
|
|
case SCANLB:
|
|
ButtonDown(SCANLB);
|
|
if (ntfb_status == SETUNE) {
|
|
switch (Event.xbutton.button) {
|
|
case 1:
|
|
timebutton = 1;
|
|
while (timebutton == 1)
|
|
if (isource == TELEVISION)
|
|
ScanDown();
|
|
break;
|
|
case 3:
|
|
if (isource == TELEVISION)
|
|
FineTuneDown();
|
|
break;
|
|
}
|
|
}
|
|
else if (ntfb_status == SETON)
|
|
ChanDown();
|
|
break;
|
|
case SCANRB:
|
|
ButtonDown(SCANRB);
|
|
if (ntfb_status == SETUNE) {
|
|
switch (Event.xbutton.button) {
|
|
case 1:
|
|
timebutton = 1;
|
|
while (timebutton)
|
|
if (isource == TELEVISION)
|
|
ScanUp();
|
|
break;
|
|
case 3:
|
|
if (isource == TELEVISION)
|
|
FineTuneUp();
|
|
break;
|
|
}
|
|
}
|
|
else if (ntfb_status == SETON)
|
|
ChanUp();
|
|
break;
|
|
case FULLSB:
|
|
ButtonDown(FULLSB);
|
|
switch (Event.xbutton.button) {
|
|
case 1:
|
|
but_pressed = TRUE;
|
|
break;
|
|
case 2:
|
|
but_pressed = TRUE;
|
|
break;
|
|
case 3:
|
|
if (!mute) {
|
|
MuteAudio();
|
|
}
|
|
else {
|
|
UnMuteAudio();
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
RedrawWindow();
|
|
}
|
|
break;
|
|
case ButtonRelease:
|
|
switch (pressed_button) {
|
|
case NTFB:
|
|
ButtonUp(NTFB);
|
|
if (but_pressed) {
|
|
if (Event.xbutton.time - t_lc >= 900) {
|
|
btime = TRUE;
|
|
but_pressed = FALSE;
|
|
}
|
|
}
|
|
|
|
if (ntfb_status == SETOFF) {
|
|
if (child_pid == -1) {
|
|
ntfb_status = SETON;
|
|
TVOn();
|
|
}
|
|
}
|
|
else if (ntfb_status == SETON) {
|
|
if (!btime) {
|
|
ntfb_status = SETUNE;
|
|
copyXPMArea(96, 79, 11, 7, 6, 50);
|
|
RedrawWindowXYWH(6, 50, 11, 7);
|
|
}
|
|
else if (btime) {
|
|
ntfb_status = SETOFF;
|
|
btime = FALSE;
|
|
ic = TRUE;
|
|
TVOff();
|
|
}
|
|
}
|
|
else if (ntfb_status == SETUNE) {
|
|
if (!btime) {
|
|
ftune[cchannel] = (rfreq - ccrfreq);
|
|
/* fprintf(stderr, "wmtv: finetune offset = %ld\n", ftune[cchannel]); */
|
|
WriteRCFile(usrConfFile, wmtv_keys);
|
|
ntfb_status = SETON;
|
|
DrawPresetChan(cchannel);
|
|
}
|
|
else if (btime) {
|
|
ntfb_status = SETOFF;
|
|
btime = FALSE;
|
|
ic = TRUE;
|
|
TVOff();
|
|
}
|
|
}
|
|
break;
|
|
case SCANLB:
|
|
ButtonUp(SCANLB);
|
|
if (ntfb_status == SETUNE)
|
|
timebutton = 0;
|
|
break;
|
|
case SCANRB:
|
|
ButtonUp(SCANRB);
|
|
if (ntfb_status == SETUNE)
|
|
timebutton = 0;
|
|
break;
|
|
case FULLSB:
|
|
ButtonUp(FULLSB);
|
|
switch (Event.xbutton.button) {
|
|
case 1: {
|
|
if (but_clicked) {
|
|
but_pressed = FALSE;
|
|
but_clicked = FALSE;
|
|
|
|
if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
|
|
{
|
|
if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
|
|
if (exe) {
|
|
pid_t pid;
|
|
char *command;
|
|
char *letters = "#nf";
|
|
char *(expansions[3]);
|
|
ntfb_status = SETOFF;
|
|
TVOff();
|
|
expansions[0] = malloc(3*sizeof(char));
|
|
snprintf(expansions[0], 3, "%d", cchannel+1);
|
|
expansions[1] = comment[cchannel];
|
|
expansions[2] = malloc(15*sizeof(char));
|
|
snprintf(expansions[2], 15, "%.3f", (double)rfreq/(double)st);
|
|
command = expand_format(exe, letters, expansions);
|
|
/* system(exe); */
|
|
child_pid = fork();
|
|
if (child_pid == (pid_t) 0) {
|
|
char *argv[4];
|
|
argv[0] = "sh";
|
|
argv[1] = "-c";
|
|
argv[2] = command;
|
|
argv[3] = NULL;
|
|
execv("/bin/sh", argv);
|
|
exit(-1);
|
|
}
|
|
free(expansions[0]);
|
|
free(expansions[2]);
|
|
free(command);
|
|
pid = waitpid(child_pid, NULL, WNOHANG);
|
|
if (pid != 0) {
|
|
child_pid = -1;
|
|
restart = TRUE;
|
|
}
|
|
/* printf("Returned pid:\n"); */
|
|
|
|
#if 0
|
|
pid = fork();
|
|
|
|
/* child */
|
|
if (pid == (pid_t) 0) {
|
|
execlp("xawtv", "xawtv", "&", (char *) 0);
|
|
}
|
|
|
|
else if (pid < (pid_t) 0) {
|
|
perror("fork");
|
|
}
|
|
|
|
/* parent */
|
|
else {
|
|
if (waitpid(pid, NULL, 0) < 0) {
|
|
perror("waitpid");
|
|
#endif
|
|
}
|
|
else {
|
|
DoFullScreen();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (but_pressed) {
|
|
t_lc = Event.xbutton.time;
|
|
x_lc = Event.xbutton.x;
|
|
y_lc = Event.xbutton.y;
|
|
but_clicked = TRUE;
|
|
but_pressed = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
case 2: {
|
|
if (but_clicked) {
|
|
but_pressed = FALSE;
|
|
but_clicked = FALSE;
|
|
|
|
if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) )
|
|
{
|
|
if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
|
|
DoFullScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (but_pressed) {
|
|
t_lc = Event.xbutton.time;
|
|
x_lc = Event.xbutton.x;
|
|
y_lc = Event.xbutton.y;
|
|
but_clicked = TRUE;
|
|
but_pressed = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
case 3:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
RedrawWindow();
|
|
break;
|
|
case VisibilityNotify:
|
|
switch(Event.xvisibility.state) {
|
|
case VisibilityFullyObscured:
|
|
ccapt = 0;
|
|
if (tfd && (ntfb_status != SETOFF) && !fmode) {
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
}
|
|
break;
|
|
case VisibilityPartiallyObscured:
|
|
ccapt = 0;
|
|
if (tfd && (ntfb_status != SETOFF) && !fmode) {
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
}
|
|
break;
|
|
case VisibilityUnobscured:
|
|
ccapt = 1;
|
|
if (tfd && (ntfb_status != SETOFF) && !fmode) {
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
RedrawWindow();
|
|
break;
|
|
case KeyPress:
|
|
if ((Event.xany.window == fmwin) && fmode) {
|
|
switch(XkbKeycodeToKeysym(display, Event.xkey.keycode, 0, 0)) {
|
|
case XK_Up:
|
|
if (isource == TELEVISION)
|
|
ChanUp();
|
|
break;
|
|
case XK_Down:
|
|
if (isource == TELEVISION)
|
|
ChanDown();
|
|
break;
|
|
case XK_Right:
|
|
VolumeUp();
|
|
break;
|
|
case XK_Left:
|
|
VolumeDown();
|
|
break;
|
|
case XK_m:
|
|
if (!mute) {
|
|
MuteAudio();
|
|
}
|
|
else {
|
|
UnMuteAudio();
|
|
}
|
|
break;
|
|
case XK_Escape:
|
|
RetScreen();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
XFlush(display);
|
|
}
|
|
usleep(50000L);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
/* ButtonDown function */
|
|
void
|
|
ButtonDown(int button)
|
|
{
|
|
switch (button) {
|
|
case NTFB:
|
|
copyXPMArea(79, 100, 12, 11, 47, 48);
|
|
RedrawWindowXYWH (47, 48, 12, 11);
|
|
break;
|
|
case SCANLB:
|
|
copyXPMArea(55, 100, 12, 11, 23, 48);
|
|
RedrawWindowXYWH(35, 48, 12, 11);
|
|
break;
|
|
case SCANRB:
|
|
copyXPMArea(67, 100, 12, 11, 35, 48);
|
|
RedrawWindowXYWH(35, 48, 12, 11);
|
|
break;
|
|
case FULLSB:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* ButtonUp function */
|
|
void
|
|
ButtonUp(int button)
|
|
{
|
|
switch (button) {
|
|
case NTFB:
|
|
copyXPMArea(79, 88, 12, 11, 47, 48);
|
|
RedrawWindowXYWH(47, 48, 12, 11);
|
|
break;
|
|
case SCANLB:
|
|
copyXPMArea(55, 88, 12, 11, 23, 48);
|
|
RedrawWindowXYWH(23, 48, 12, 11);
|
|
break;
|
|
case SCANRB:
|
|
copyXPMArea(67, 88, 12, 11, 35, 48);
|
|
RedrawWindowXYWH(35, 48, 12, 11);
|
|
break;
|
|
case FULLSB:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* TVOn function */
|
|
void
|
|
TVOn(void)
|
|
{
|
|
int i;
|
|
Window junkwin;
|
|
int rx, ry;
|
|
char *p;
|
|
|
|
XWindowAttributes winattr;
|
|
|
|
if (!XGetWindowAttributes (display, iconwin, &winattr)) {
|
|
fprintf(stderr, "wmtv: error getting winattr of iconwin\n");
|
|
}
|
|
|
|
if (!XTranslateCoordinates(display, iconwin, winattr.root,
|
|
-winattr.border_width,
|
|
-winattr.border_width,
|
|
&rx, &ry, &junkwin)) {
|
|
fprintf(stderr, "wmtv: error translating coordinates\n");
|
|
}
|
|
|
|
/* This part was taken from xawtv's source code */
|
|
switch (system("v4l-conf -q")) {
|
|
case -1: /* can't run */
|
|
fprintf(stderr,"could'nt start v4l-conf\n");
|
|
break;
|
|
case 0: /* ok */
|
|
break;
|
|
default: /* non-zero return */
|
|
fprintf(stderr,"v4l-conf had some trouble, "
|
|
"trying to continue anyway\n");
|
|
}
|
|
/* End of "stolen" part */
|
|
InitConfig();
|
|
GetFrameBuffer();
|
|
InitPalette();
|
|
|
|
ccapt = 1;
|
|
|
|
vwin.x = rx;
|
|
vwin.y = ry + 5;
|
|
|
|
vwin.width = 64;
|
|
vwin.height = 39;
|
|
|
|
vclip[0].x = 0; /* Clipping Rect 1 */
|
|
vclip[0].y = 0;
|
|
vclip[0].width = 5;
|
|
vclip[0].height = 39;
|
|
vclip[1].x = 59; /* Clipping Rect 2 */
|
|
vclip[1].y = 0;
|
|
vclip[1].width = 5;
|
|
vclip[1].height = 39;
|
|
|
|
vwin.clips = vclip;
|
|
vwin.clipcount = 2;
|
|
|
|
vchn.channel = tvsource;
|
|
vaud.audio = tvsource;
|
|
|
|
if (source) {
|
|
p = source;
|
|
if (*p == 'T')
|
|
isource = TELEVISION;
|
|
else if (*p == 'C') {
|
|
isource = COMPOSITE;
|
|
while (isalpha(*p))
|
|
++p;
|
|
compchannel = atoi(p);
|
|
}
|
|
else if (*p == 'S')
|
|
isource = SVIDEO;
|
|
}
|
|
|
|
if (!cnotune) {
|
|
if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0)
|
|
perror("ioctl VIDIOCGTUNER");
|
|
if (vtun.flags & VIDEO_TUNER_LOW)
|
|
st = 16000;
|
|
else
|
|
st = 16;
|
|
}
|
|
|
|
if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0)
|
|
perror("ioctl VIDIOCGCHAN");
|
|
|
|
if (vchn.flags & VIDEO_VC_AUDIO) {
|
|
if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCGAUDIO");
|
|
}
|
|
|
|
if (vaud.flags & VIDEO_AUDIO_MUTE) {
|
|
vaud.flags &= ~VIDEO_AUDIO_MUTE; /* Unmute */
|
|
vaud.volume = 0xFFFF;
|
|
}
|
|
|
|
if (isource == TELEVISION) {
|
|
for (i=0; i < CHAN_ENTRIES; i++) {
|
|
if (!strcmp(cname[cchannel], tvtuner[i].name)) {
|
|
rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
|
|
ccrfreq = rfreq - ftune[cchannel];
|
|
break;
|
|
}
|
|
}
|
|
DrawPresetChan(cchannel);
|
|
}
|
|
else if (isource == COMPOSITE) {
|
|
DrawPresetChan(compchannel);
|
|
}
|
|
else if (isource == SVIDEO) {
|
|
DrawPresetChan(-1);
|
|
}
|
|
|
|
if (vchn.flags & VIDEO_VC_AUDIO) {
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
|
|
}
|
|
|
|
if (ioctl(tfd, VIDIOCSCHAN, &vchn) < 0)
|
|
perror("ioctl VIDIOCSCHAN");
|
|
|
|
if (!cnotune) {
|
|
if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
|
|
perror("ioctl VIDIOCSFREQ");
|
|
}
|
|
|
|
if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0)
|
|
perror("ioctl VIDIOCSWIN");
|
|
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
|
|
|
|
/* TVOff function */
|
|
void
|
|
TVOff(void)
|
|
{
|
|
ccapt = 0;
|
|
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0)
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
|
|
vaud.audio = tvsource;
|
|
vaud.volume = 0;
|
|
vaud.flags |= VIDEO_AUDIO_MUTE;
|
|
|
|
if (vchn.flags & VIDEO_VC_AUDIO) {
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
}
|
|
|
|
close(tfd);
|
|
copyXPMArea(66, 79, 11, 7, 6, 50);
|
|
RedrawWindowXYWH(6, 50, 11, 7);
|
|
}
|
|
|
|
|
|
/* VolumeUp function */
|
|
void
|
|
VolumeUp(void)
|
|
{
|
|
if(vchn.flags & VIDEO_VC_AUDIO) {
|
|
if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
|
|
fprintf(stderr, "Warning: v4l device does not support volume control.\n");
|
|
else if (vaud.volume <= 0xEEEE) {
|
|
vaud.audio = tvsource;
|
|
vaud.volume += 0x1111;
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* VoumeDown function */
|
|
void
|
|
VolumeDown(void)
|
|
{
|
|
if (vchn.flags & VIDEO_VC_AUDIO) {
|
|
if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
|
|
fprintf(stderr, "Warning: v4l device does not support volume control.\n");
|
|
else if (vaud.volume >= 0x1111) {
|
|
vaud.audio = tvsource;
|
|
vaud.volume -= 0x1111;
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* MuteAudio function */
|
|
void
|
|
MuteAudio(void)
|
|
{
|
|
if (vchn.flags & VIDEO_VC_AUDIO) {
|
|
vaud.audio = tvsource;
|
|
/* vaud.volume = 0; */
|
|
vaud.flags |= VIDEO_AUDIO_MUTE;
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
}
|
|
mute = TRUE;
|
|
}
|
|
|
|
|
|
/* UnMuteAudio function */
|
|
void
|
|
UnMuteAudio(void)
|
|
{
|
|
if ((vchn.flags & VIDEO_VC_AUDIO) && (vaud.flags & VIDEO_AUDIO_MUTE)) {
|
|
vaud.audio = tvsource;
|
|
/* vaud.volume = (0xFFFF/2)+1; */
|
|
vaud.flags &= ~VIDEO_AUDIO_MUTE;
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
}
|
|
mute = FALSE;
|
|
}
|
|
|
|
|
|
/* ScanUp function */
|
|
void
|
|
ScanUp(void)
|
|
{
|
|
rfreq += 2;
|
|
usleep(50000L);
|
|
if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
|
|
perror("ioctl VIDIOCSFREQ");
|
|
}
|
|
usleep(10000L);
|
|
vtun.tuner = 0;
|
|
if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
|
|
perror("ioctl VIDIOCGTUNER");
|
|
}
|
|
if (vtun.signal == 0xFFFF) {
|
|
timebutton = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* ScanDown function */
|
|
void
|
|
ScanDown(void)
|
|
{
|
|
rfreq -= 2;
|
|
usleep(50000L);
|
|
if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
|
|
perror("ioctl VIDIOCSFREQ");
|
|
}
|
|
usleep(10000L);
|
|
vtun.tuner = 0;
|
|
if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
|
|
perror("ioctl VIDIOCGTUNER");
|
|
}
|
|
if (vtun.signal == 0xFFFF) {
|
|
timebutton = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* FineTuneUp function */
|
|
void
|
|
FineTuneUp(void)
|
|
{
|
|
rfreq += 1;
|
|
if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
|
|
perror("ioctl VIDIOCSFREQ");
|
|
}
|
|
}
|
|
|
|
|
|
/* FineTuneDown function */
|
|
void
|
|
FineTuneDown(void)
|
|
{
|
|
rfreq -= 1;
|
|
if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) {
|
|
perror("ioctl VIDIOCSFREQ");
|
|
}
|
|
}
|
|
|
|
|
|
/* ChanUp function */
|
|
void
|
|
ChanUp(void)
|
|
{
|
|
int i;
|
|
if (cchannel < maxpst)
|
|
++cchannel;
|
|
for (i=0; i < CHAN_ENTRIES; i++) {
|
|
if (!strcmp(cname[cchannel], tvtuner[i].name)) {
|
|
rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
|
|
ccrfreq = rfreq - ftune[cchannel];
|
|
break;
|
|
}
|
|
}
|
|
|
|
DrawPresetChan(cchannel);
|
|
if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
|
|
perror("ioctl VIDIOCSFREQ");
|
|
}
|
|
|
|
|
|
/* ChanDown function */
|
|
void
|
|
ChanDown(void)
|
|
{
|
|
int i;
|
|
if (cchannel != 0)
|
|
--cchannel;
|
|
for (i=0; i < CHAN_ENTRIES; i++) {
|
|
if (!strcmp(cname[cchannel], tvtuner[i].name)) {
|
|
rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel];
|
|
ccrfreq = rfreq - ftune[cchannel];
|
|
break;
|
|
}
|
|
}
|
|
|
|
DrawPresetChan(cchannel);
|
|
if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0)
|
|
perror("ioctl VIDIOCSFREQ");
|
|
}
|
|
|
|
|
|
/* DrawPresetChan function */
|
|
void
|
|
DrawPresetChan(int cchannel)
|
|
{
|
|
char temp[10];
|
|
char *p = temp;
|
|
int j=0;
|
|
int k=6;
|
|
|
|
if (isource == TELEVISION) {
|
|
sprintf(temp, "%02d", cchannel+1);
|
|
|
|
if (*p == '0') {
|
|
copyXPMArea(66, 79, 5, 7, k, 50);
|
|
k += 6;
|
|
j++;
|
|
p++;
|
|
}
|
|
while (j < 2) {
|
|
copyXPMArea((*p-'0')*6 + 1, 79, 5, 7, k, 50);
|
|
k += 6;
|
|
p++;
|
|
j++;
|
|
}
|
|
}
|
|
|
|
else if (isource == COMPOSITE) {
|
|
copyXPMArea (109, 79, 5, 7, 6, 50);
|
|
copyXPMArea ((compchannel*6) + 1, 79, 5, 7, 12, 50);
|
|
}
|
|
|
|
else if (isource == SVIDEO) {
|
|
copyXPMArea(116, 79, 11, 7, 6, 50);
|
|
}
|
|
|
|
RedrawWindowXYWH(6, 50, 11, 7);
|
|
}
|
|
|
|
|
|
/* ParseRCFile function */
|
|
void
|
|
ParseRCFile(const char *filename, rckeys *keys)
|
|
{
|
|
char *p;
|
|
char temp[128];
|
|
char *tokens = " =\t\n";
|
|
FILE *fp;
|
|
int key = 0;
|
|
|
|
if ((fp = fopen(filename, "r")) == NULL) {
|
|
fprintf(stderr, "wmtv: %s\n", strerror(errno));
|
|
norcfile = 1;
|
|
return;
|
|
}
|
|
norcfile = 0;
|
|
while (fgets(temp, 128, fp)) {
|
|
if (temp[0] != '\n') {
|
|
p = strtok(temp, tokens);
|
|
for (key=0; keys[key].label; key++) {
|
|
if ((!strcmp(p, keys[key].label))) {
|
|
p = strtok(NULL, tokens);
|
|
free(*keys[key].var);
|
|
*keys[key].var = strdup(p);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
/* ParseRCFile2 function */
|
|
void
|
|
ParseRCFile2(const char *filename)
|
|
{
|
|
int menu = FALSE;
|
|
char temp[128], name[128];
|
|
FILE *fp;
|
|
int len, i = 0;
|
|
|
|
if ((fp = fopen(filename, "r")) == NULL) {
|
|
fprintf(stderr, "wmtv: %s\n", strerror(errno));
|
|
norcfile = 1;
|
|
return;
|
|
}
|
|
norcfile = 0;
|
|
while (fgets(temp, 128, fp)) {
|
|
if (*temp != '\n') {
|
|
if (menu) {
|
|
ftune[i]=0;
|
|
if(sscanf(temp, " %s %n(%ld) %n", name, &len, &ftune[i], &len)>=1) {
|
|
char *pos;
|
|
cname[i]=strdup(name);
|
|
comment[i]=temp[len]?strdup(temp+len):"";
|
|
/* Remove the end-of-line symbol */
|
|
for (pos = comment[i]; *pos != '\0'; pos++) {
|
|
if (*pos == '\n') {
|
|
*pos = '\0';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(++i>=MAXCHAN)
|
|
break;
|
|
}
|
|
else if (strchr(temp, '[')) {
|
|
menu = TRUE;
|
|
}
|
|
}
|
|
}
|
|
tpst = i;
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
/* WriteRCFile function */
|
|
void
|
|
WriteRCFile(const char *filename, rckeys *keys)
|
|
{
|
|
long i;
|
|
FILE *fp;
|
|
int key;
|
|
|
|
if ((fp = fopen(filename, "w")) == NULL) {
|
|
fprintf(stderr, "wmtv: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
for (key=0; keys[key].label; key++)
|
|
if (*keys[key].var)
|
|
fprintf(fp, "%s = %s\n", keys[key].label, *keys[key].var);
|
|
|
|
fprintf(fp, "\n[channel]\n");
|
|
|
|
for (i = 0; i <= maxpst; i++)
|
|
fprintf(fp, "%s (%ld)\t%s\n", cname[i], ftune[i], comment[i]);
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
/* InitPalette function */
|
|
void
|
|
InitPalette(void)
|
|
{
|
|
if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
|
|
perror ("ioctl VIDIOCGFBUF");
|
|
exit(-1);
|
|
}
|
|
if (vfb.base == NULL) {
|
|
fprintf(stderr, "wmtv: no physical frame buffer access\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
if (ioctl(tfd, VIDIOCGPICT, &vpic) < 0) {
|
|
perror("ioctl VIDIOCGPICT");
|
|
}
|
|
vpic.depth = vfb.depth;
|
|
switch(vpic.depth) {
|
|
case 8:
|
|
vpic.palette = VIDEO_PALETTE_HI240;
|
|
break;
|
|
case 15:
|
|
vpic.palette = VIDEO_PALETTE_RGB555;
|
|
break;
|
|
case 16:
|
|
vpic.palette = VIDEO_PALETTE_RGB565;
|
|
break;
|
|
case 24:
|
|
vpic.palette = VIDEO_PALETTE_RGB24;
|
|
break;
|
|
case 32:
|
|
vpic.palette = VIDEO_PALETTE_RGB32;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "wmtv: unsupported depth %d\n", vpic.depth);
|
|
exit(-1);
|
|
}
|
|
if (ioctl(tfd, VIDIOCSPICT, &vpic) < 0) {
|
|
perror("ioctl VIDIOCSPICT");
|
|
}
|
|
}
|
|
/* InitConfig function */
|
|
void
|
|
InitConfig(void)
|
|
{
|
|
int i;
|
|
|
|
ParseRCFile(usrConfFile, wmtv_keys);
|
|
ParseRCFile2(usrConfFile);
|
|
|
|
if (norcfile) {
|
|
ParseRCFile(sysConfFile, wmtv_keys);
|
|
ParseRCFile2(sysConfFile);
|
|
|
|
if (norcfile) {
|
|
fprintf(stderr, "wmtv: error - config file not found\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (maxpreset != NULL)
|
|
maxpst = atoi(maxpreset) - 1;
|
|
else
|
|
maxpst = 1;
|
|
|
|
if ((tpst) != atoi(maxpreset)) {
|
|
fprintf(stderr, "wmtv: error - maxpreset value does not match total channel value\n");
|
|
exit(1);
|
|
}
|
|
if ((tfd = open(dev, O_RDWR)) < 0) {
|
|
perror("open failed");
|
|
}
|
|
card_present = TRUE;
|
|
|
|
if (norm)
|
|
for (i=0; i < CHAN_NAMES; i++) {
|
|
if (!strcmp(chan_names[i].cname, norm)) {
|
|
freqnorm = chan_names[i].cind;
|
|
}
|
|
}
|
|
|
|
if (freqnorm == -1) {
|
|
fprintf(stderr, "wmtv: error - set freqnorm in config file\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (ioctl(tfd, VIDIOCGCAP, &vcap) < 0) {
|
|
perror("ioctl VIDIOCGCAP");
|
|
}
|
|
|
|
if (!(vcap.type & VID_TYPE_SCALES)) {
|
|
fprintf(stderr, "%s: video device does not support scalling\n", progname);
|
|
exit(1);
|
|
}
|
|
if (!(vcap.type & VID_TYPE_CLIPPING)) {
|
|
fprintf(stderr, "%s: video device does not support clipping\n", progname);
|
|
}
|
|
|
|
if (fullscreen) {
|
|
fswidth = atoi(strtok(fullscreen, "x\n"));
|
|
fsheight = atoi(strtok(NULL, "x\n"));
|
|
}
|
|
else {
|
|
fswidth = 640;
|
|
fsheight = 480;
|
|
}
|
|
|
|
if (source) {
|
|
for (i=0; i < vcap.channels; i++) {
|
|
vchn.channel = i;
|
|
if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0) {
|
|
perror("ioctl VIDIOCGCHAN");
|
|
}
|
|
if (!strcmp(vchn.name, source)) {
|
|
if (vchn.tuners)
|
|
cnotune = 0;
|
|
else
|
|
cnotune = 1;
|
|
|
|
vsource = 1;
|
|
tvsource = vchn.channel;
|
|
|
|
if ((ioctl(tfd, VIDIOCSCHAN, &vchn)) < 0)
|
|
perror("ioctl VIDIOCSCHAN");
|
|
}
|
|
}
|
|
if (!vsource)
|
|
fprintf(stderr, "wmtv: invalid source in config file\n");
|
|
}
|
|
|
|
if (mode) {
|
|
if (!cnotune) {
|
|
vtun.tuner = 0;
|
|
if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) {
|
|
perror("ioctl VIDIOCGTUNER");
|
|
}
|
|
|
|
if (!strcmp(mode, "pal")) {
|
|
if (vtun.flags & VIDEO_TUNER_PAL) {
|
|
vtun.mode = VIDEO_MODE_PAL;
|
|
if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
|
|
perror("ioctl VIDIOCSTUNER");
|
|
}
|
|
}
|
|
}
|
|
if (!strcmp(mode, "ntsc")) {
|
|
if (vtun.flags & VIDEO_TUNER_NTSC) {
|
|
vtun.mode = VIDEO_MODE_NTSC;
|
|
if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
|
|
perror("ioctl VIDIOCSTUNER");
|
|
}
|
|
}
|
|
}
|
|
if (!strcmp(mode, "secam")) {
|
|
if (vtun.flags & VIDEO_TUNER_SECAM) {
|
|
vtun.mode = VIDEO_MODE_SECAM;
|
|
if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) {
|
|
perror("ioctl VIDIOCSTUNER");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=0; i < vcap.audios; i++) {
|
|
vaud.audio = i;
|
|
if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0) {
|
|
perror("ioctl VIDIOCGAUDIO");
|
|
}
|
|
if (!(vaud.flags & VIDEO_AUDIO_MUTE)) {
|
|
vaud.flags |= VIDEO_AUDIO_MUTE;
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) {
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) {
|
|
perror("ioctl VIDIOCGFBUF");
|
|
}
|
|
}
|
|
|
|
/* GetFrameBuffer function */
|
|
void
|
|
GetFrameBuffer(void)
|
|
{
|
|
#if 0
|
|
void *baseaddr = NULL;
|
|
int evbr, erbr, flr = 0;
|
|
int bankr, memr, depth;
|
|
int i, n;
|
|
int bytesperline, bitsperpixel;
|
|
XPixmapFormatValues *pf;
|
|
#endif
|
|
|
|
if (!XGetWindowAttributes(display, DefaultRootWindow(display), &Winattr)) {
|
|
fprintf(stderr, "wmtv: error getting winattr of root\n");
|
|
}
|
|
|
|
#if 0
|
|
depth = Winattr.depth;
|
|
|
|
if (XF86DGAQueryExtension(display, &evbr, &erbr)) {
|
|
XF86DGAQueryDirectVideo(display, XDefaultScreen(display), &flr);
|
|
if (flr & XF86DGADirectPresent) {
|
|
XF86DGAGetVideoLL(display, XDefaultScreen(display),
|
|
(int *) &baseaddr, &bytesperline, &bankr, &memr);
|
|
}
|
|
}
|
|
else {
|
|
fprintf(stderr, "wmtv: error - XF86DGA Extensions not available\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
pf = XListPixmapFormats(display, &n);
|
|
for (i=0; i < n; i++) {
|
|
if (pf[i].depth == depth) {
|
|
depth = pf[i].bits_per_pixel;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bitsperpixel = (depth+7) & 0xf8;
|
|
bytesperline *= bitsperpixel/8;
|
|
|
|
vfb.base = baseaddr;
|
|
vfb.height = Winattr.height;
|
|
vfb.width = Winattr.width;
|
|
vfb.depth = bitsperpixel;
|
|
vfb.bytesperline = bytesperline;
|
|
|
|
if (Winattr.depth == 15)
|
|
vfb.depth = 15;
|
|
|
|
if (ioctl(tfd, VIDIOCSFBUF, &vfb) < 0) {
|
|
perror("ioctl VIDIOCSFBUF");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* DoFullScreen function */
|
|
void
|
|
DoFullScreen(void)
|
|
{
|
|
int i;
|
|
int evbr, erbr = 0;
|
|
int rx, ry;
|
|
unsigned long back_pix, fore_pix;
|
|
unsigned int borderwidth = 0;
|
|
|
|
Window junkwin;
|
|
XSizeHints fmsizehints;
|
|
XWMHints fmxwmhints;
|
|
XGCValues gcv;
|
|
unsigned long gcm;
|
|
unsigned long valuemask;
|
|
|
|
XSetWindowAttributes fmWinattr;
|
|
XWindowAttributes fmwinattr;
|
|
|
|
|
|
ccapt = 0;
|
|
if (ioctl (tfd, VIDIOCCAPTURE, &ccapt) < 0) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
|
|
fmsizehints.x = 0;
|
|
fmsizehints.y = 0;
|
|
fmsizehints.width = fswidth;
|
|
fmsizehints.height = fsheight;
|
|
fmsizehints.max_width = vcap.maxwidth;
|
|
fmsizehints.max_height = vcap.maxheight;
|
|
fmsizehints.min_width = fswidth;
|
|
fmsizehints.min_height = fsheight;
|
|
fmsizehints.flags = (USPosition | USSize | PSize | PMinSize | PMaxSize);
|
|
|
|
valuemask = 0;
|
|
|
|
back_pix = WhitePixel(display, DefaultScreen(display));
|
|
fore_pix = BlackPixel(display, DefaultScreen(display));
|
|
|
|
fmwin = XCreateWindow(display, DefaultRootWindow(display), fmsizehints.x,
|
|
fmsizehints.y, fmsizehints.width, fmsizehints.height,
|
|
borderwidth, CopyFromParent, InputOutput,
|
|
CopyFromParent, valuemask, &fmWinattr);
|
|
|
|
|
|
XSetWMNormalHints(display, fmwin, &fmsizehints);
|
|
|
|
gcm = (GCForeground | GCBackground | GCGraphicsExposures);
|
|
gcv.foreground = fore_pix;
|
|
gcv.background = back_pix;
|
|
gcv.graphics_exposures = 0;
|
|
|
|
fmGC = XCreateGC(display, DefaultRootWindow(display), gcm, &gcv);
|
|
|
|
XSelectInput(display, fmwin, ButtonPressMask | ExposureMask |
|
|
ButtonReleaseMask | PointerMotionMask |
|
|
StructureNotifyMask | VisibilityChangeMask | KeyPressMask );
|
|
|
|
fmxwmhints.flags = StateHint;
|
|
fmxwmhints.initial_state = NormalState;
|
|
|
|
XSetWMHints(display, fmwin, &fmxwmhints);
|
|
|
|
|
|
if (XF86VidModeQueryExtension(display, &evbr, &erbr)) {
|
|
vidmode = TRUE;
|
|
}
|
|
else {
|
|
fprintf(stderr, "wmtv: xf86mode extension not present\n");
|
|
fprintf(stderr, " switch disabled\n");
|
|
}
|
|
|
|
|
|
XMapWindow(display, fmwin);
|
|
|
|
usleep(50000L);
|
|
if (!XGetWindowAttributes(display, fmwin, &fmwinattr)) {
|
|
fprintf(stderr, "wmtv: error getting winattr of fmwin\n");
|
|
}
|
|
|
|
usleep(50000L);
|
|
if (!XTranslateCoordinates(display, fmwin, DefaultRootWindow(display),
|
|
-fmwinattr.border_width,
|
|
-fmwinattr.border_width,
|
|
&rx, &ry, &junkwin)) {
|
|
fprintf(stderr, "wmtv: error translating coordinates for fmwin");
|
|
}
|
|
|
|
vswin.width = fswidth;
|
|
vswin.height = fsheight;
|
|
vswin.x = fmsizehints.x + rx;
|
|
vswin.y = fmsizehints.y + ry;
|
|
vswin.clipcount = 0;
|
|
|
|
if (ioctl(tfd, VIDIOCSWIN, &vswin) < 0) {
|
|
perror("ioctl VIDIOCSWIN");
|
|
}
|
|
|
|
ccapt = 1;
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
fmode = TRUE;
|
|
|
|
if (vidmode) {
|
|
XF86VidModeGetModeLine(display, XDefaultScreen(display), &dcret, &scmode);
|
|
XF86VidModeGetAllModeLines(display, XDefaultScreen(display), &tml, &modelines);
|
|
|
|
for (i=0; i < tml; i++) {
|
|
if ((modelines[i]->hdisplay == fswidth) &&
|
|
(modelines[i]->vdisplay == fsheight)) {
|
|
fullscreenmode = modelines[i];
|
|
mode_present = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!mode_present) {
|
|
fprintf(stderr, "wmtv: mode line for resolution %d x %d not found\n", vcap.maxwidth, vcap.maxheight);
|
|
}
|
|
|
|
XRaiseWindow(display, fmwin);
|
|
if (mode_present) {
|
|
|
|
XF86VidModeSwitchToMode(display, XDefaultScreen(display), fullscreenmode);
|
|
XF86VidModeSetViewPort(display, XDefaultScreen(display), vswin.x, vswin.y);
|
|
XGrabPointer(display, fmwin, True, 0, GrabModeAsync, GrabModeAsync,
|
|
fmwin, None, CurrentTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* RetScreen function */
|
|
void
|
|
RetScreen()
|
|
{
|
|
int i;
|
|
XF86VidModeModeInfo *scm = NULL;
|
|
|
|
ccapt = 0;
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt)) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
|
|
if (mode_present) {
|
|
for (i = 0; i < tml; i++) {
|
|
if ((modelines[i]->hdisplay == Winattr.width) &&
|
|
(modelines[i]->vdisplay==Winattr.height))
|
|
scm = modelines[i];
|
|
}
|
|
|
|
scm->dotclock = dcret;
|
|
scm->hdisplay = scmode.hdisplay;
|
|
scm->hsyncstart = scmode.hsyncstart;
|
|
scm->hsyncend = scmode.hsyncend;
|
|
scm->htotal = scmode.htotal;
|
|
scm->vdisplay = scmode.vdisplay;
|
|
scm->vsyncstart = scmode.vsyncstart;
|
|
scm->vsyncend = scmode.vsyncend;
|
|
scm->vtotal = scmode.vtotal;
|
|
scm->flags = scmode.flags;
|
|
/*
|
|
scm->privsize = scmode.privsize;
|
|
scm->private = scmode.private;
|
|
*/
|
|
|
|
XClearWindow(display, fmwin);
|
|
XFreeGC(display, fmGC);
|
|
XMapRaised(display, fmwin);
|
|
XUnmapWindow(display, fmwin);
|
|
XUngrabPointer(display, CurrentTime);
|
|
}
|
|
else {
|
|
XClearWindow(display, fmwin);
|
|
XFreeGC(display, fmGC);
|
|
XMapRaised(display, fmwin);
|
|
XUnmapWindow(display, fmwin);
|
|
}
|
|
|
|
if (vidmode && mode_present) {
|
|
XF86VidModeSwitchToMode(display, XDefaultScreen(display), scm);
|
|
vidmode = FALSE;
|
|
}
|
|
fmode = FALSE;
|
|
mode_present = FALSE;
|
|
|
|
ccapt = 1;
|
|
if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0) {
|
|
perror("ioctl VIDIOCSWIN");
|
|
}
|
|
|
|
if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) {
|
|
perror("ioctl VIDIOCCAPTURE");
|
|
}
|
|
RedrawWindow();
|
|
}
|
|
|
|
/* GrabImage function */
|
|
void
|
|
GrabImage(void)
|
|
{
|
|
}
|
|
|
|
/* Usage function */
|
|
void
|
|
Usage(void)
|
|
{
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "wmtv v%s, Copyright (c) 1999 Wee Liang <wliang@tartarus.uwa.edu.au>\n", VERSION);
|
|
fprintf(stderr, "usage: wmtv [%s]\n", OPTIONS);
|
|
fprintf(stderr, " -c, --device <file>\tsets video4linux device to use\n");
|
|
fprintf(stderr, " -d, --display <host:vs>\tsets display name\n");
|
|
fprintf(stderr, " -g, --geometry <{+-}XP{+-}YP>\tsets geometry\n");
|
|
fprintf(stderr, " -b, --bpp\t\t\tdisplay color depth\n");
|
|
fprintf(stderr, " -e, --exe <filename>\t\tprogram to execute\n");
|
|
fprintf(stderr, " -v, --version\t\t\tprints version information\n");
|
|
fprintf(stderr, " -h, --help\t\t\tprints this message\n");
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
|
|
/* Version function */
|
|
void
|
|
Version(void)
|
|
{
|
|
fprintf(stderr, "wmtv version %s\n", VERSION);
|
|
}
|