1581 lines
33 KiB
C
1581 lines
33 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 <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <linux/videodev.h>
|
|
#include <linux/soundcard.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xmd.h>
|
|
#include <X11/StringDefs.h>
|
|
#include <X11/keysym.h>
|
|
#include <X11/xpm.h>
|
|
#include <X11/extensions/shape.h>
|
|
#include <X11/extensions/xf86dga.h>
|
|
#include <X11/extensions/xf86vmode.h>
|
|
|
|
#include "wmgeneral/wmgeneral.h"
|
|
#include "wmgeneral/misc.h"
|
|
#include "wmtv-master.xpm"
|
|
#include "channels.h"
|
|
|
|
|
|
/* Defines */
|
|
#define VERSION "0.6.5"
|
|
|
|
#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 100
|
|
#define OPTIONS "hvd:g:e:b:"
|
|
|
|
#define TELEVISION 0
|
|
#define COMPOSITE 1
|
|
#define SVIDEO 2
|
|
|
|
|
|
/* Global Variables */
|
|
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;
|
|
|
|
unsigned long ccrfreq;
|
|
unsigned long rfreq;
|
|
unsigned long st;
|
|
unsigned long offset;
|
|
|
|
char *norm = NULL;
|
|
char *source;
|
|
char *mode = NULL;
|
|
char *fullscreen = NULL;
|
|
int freqnorm = -1;
|
|
char *cname[MAXCHAN];
|
|
char *wcname[MAXCHAN];
|
|
int ftune[MAXCHAN];
|
|
char *progname;
|
|
char *dev = "/dev/video";
|
|
|
|
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 *);
|
|
void InitConfig(void);
|
|
void InitPalette(void);
|
|
|
|
void Usage(void);
|
|
void Version(void);
|
|
|
|
|
|
/* main function */
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int i, c, opind;
|
|
// pid_t pid;
|
|
char cfile[128];
|
|
static struct option long_options[] = {
|
|
{"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]);
|
|
|
|
strncpy(cfile, (char *)getenv("HOME"), sizeof(char)*128);
|
|
strcat(cfile, "/.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 '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 */
|
|
|
|
/* wmtv main loop */
|
|
while (1)
|
|
{
|
|
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 {
|
|
i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
|
|
switch (i) {
|
|
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
|
|
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
|
|
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:
|
|
i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
|
|
switch (i) {
|
|
case NTFB:
|
|
ButtonUp(NTFB);
|
|
if (but_pressed) {
|
|
if (Event.xbutton.time - t_lc >= 900) {
|
|
btime = TRUE;
|
|
but_pressed = FALSE;
|
|
}
|
|
}
|
|
|
|
if (ntfb_status == SETOFF) {
|
|
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) {
|
|
offset = (rfreq - ccrfreq);
|
|
// fprintf(stderr, "wmtv: finetune offset = %ld\n", offset);
|
|
WriteRCFile(cfile);
|
|
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) {
|
|
ntfb_status = SETOFF;
|
|
TVOff();
|
|
system(exe);
|
|
/*
|
|
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");
|
|
*/
|
|
}
|
|
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(XKeycodeToKeysym(display, Event.xkey.keycode, 0)) {
|
|
case XK_Up:
|
|
if (isource == TELEVISION)
|
|
ChanUp();
|
|
break;
|
|
case XK_Down:
|
|
if (isource == TELEVISION)
|
|
ChanDown();
|
|
break;
|
|
case XK_Right:
|
|
if (isource == TELEVISION)
|
|
FineTuneUp();
|
|
break;
|
|
case XK_Left:
|
|
if (isource == TELEVISION)
|
|
FineTuneDown();
|
|
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");
|
|
}
|
|
|
|
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/2)+1;
|
|
}
|
|
|
|
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.volume <= 0xFFFF) {
|
|
vaud.audio = tvsource;
|
|
vaud.volume += (0xFFFF/10);
|
|
if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
|
|
perror("ioctl VIDIOCSAUDIO");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* VoumeDown function */
|
|
void
|
|
VolumeDown(void)
|
|
{
|
|
if (vchn.flags & VIDEO_VC_AUDIO) {
|
|
if (vaud.volume > 0) {
|
|
vaud.audio = tvsource;
|
|
vaud.volume -= (0xFFFF/10);
|
|
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);
|
|
|
|
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,*q;
|
|
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)) {
|
|
key = 0;
|
|
q = strdup(temp);
|
|
if (*q != '\n') {
|
|
q = strtok(q, tokens);
|
|
while (key >= 0 && keys[key].label) {
|
|
if ((!strcmp(q, keys[key].label))) {
|
|
p = strtok(NULL, tokens);
|
|
free(*keys[key].var);
|
|
*keys[key].var = strdup(p);
|
|
key = -1;
|
|
} else key++;
|
|
}
|
|
}
|
|
free(q);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
/* ParseRCFile2 function */
|
|
void
|
|
ParseRCFile2(const char *filename)
|
|
{
|
|
int menu = FALSE;
|
|
char temp[128];
|
|
char tp[10];
|
|
char *tokens = " \t\n()";
|
|
char *q, *p;
|
|
FILE *fp;
|
|
int 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)) {
|
|
q = strdup(temp);
|
|
if (*q != '\n') {
|
|
q = strtok(q, tokens);
|
|
if (menu) {
|
|
cname[i] = (char *)malloc(sizeof(q));
|
|
strncpy(cname[i], q, sizeof(q));
|
|
p = q;
|
|
p = strtok(NULL, tokens);
|
|
if (p != NULL) {
|
|
if (*p == '-') {
|
|
p++;
|
|
ftune[i] = -1*atoi(p);
|
|
}
|
|
else if (*p == '+') {
|
|
p++;
|
|
ftune[i] = atoi(p);
|
|
}
|
|
else {
|
|
ftune[i] = atoi(p);
|
|
}
|
|
}
|
|
else {
|
|
ftune[i] = 0;
|
|
}
|
|
wcname[i] = (char *)malloc(sizeof(cname[i])+sizeof(p));
|
|
wcname[i] = strdup(cname[i]);
|
|
sprintf(tp, " (%d) ", ftune[i]);
|
|
strcat(wcname[i], tp);
|
|
i++;
|
|
tpst = i;
|
|
}
|
|
if ((q = strchr(q, '[')) != NULL) {
|
|
menu = TRUE;
|
|
}
|
|
}
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
/* WriteRCFile function */
|
|
void
|
|
WriteRCFile(const char *filename)
|
|
{
|
|
int i;
|
|
char temp[128];
|
|
char tp[10];
|
|
char *tokens = " \t\n()";
|
|
char *q;
|
|
FILE *fp;
|
|
|
|
if ((fp = fopen(filename, "r+")) == NULL) {
|
|
fprintf(stderr, "wmtv: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
|
|
while (fgets(temp, 128, fp)) {
|
|
q = strdup(temp);
|
|
if (*q != '\n') {
|
|
q = strtok(temp, tokens);
|
|
if ((q = strchr(q, '[')) != NULL) {
|
|
for (i = 0; i <= maxpst; i++) {
|
|
// fprintf(stderr, "offset is %ld\n", offset);
|
|
sprintf(tp, " (%ld) ", offset);
|
|
strtok(wcname[cchannel], tokens);
|
|
strcat(wcname[cchannel], tp);
|
|
fputs(wcname[i], fp);
|
|
fputs("\n", fp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
char temp[128];
|
|
|
|
strcpy(temp, "/etc/wmtvrc");
|
|
ParseRCFile(temp, wmtv_keys);
|
|
ParseRCFile2(temp);
|
|
|
|
strncpy(temp, (char *)getenv("HOME"), (sizeof(char)*128));
|
|
strcat(temp, "/.wmtvrc");
|
|
ParseRCFile(temp, wmtv_keys);
|
|
ParseRCFile2(temp);
|
|
|
|
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)
|
|
{
|
|
void *baseaddr = NULL;
|
|
int evbr, erbr, flr = 0;
|
|
int bankr, memr, depth;
|
|
int i, n;
|
|
int bytesperline, bitsperpixel;
|
|
XPixmapFormatValues *pf;
|
|
|
|
if (!XGetWindowAttributes(display, DefaultRootWindow(display), &Winattr)) {
|
|
fprintf(stderr, "wmtv: error getting winattr of root\n");
|
|
}
|
|
|
|
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; /* Taken from */
|
|
bytesperline = Winattr.width * bitsperpixel / 8; /* Gerd Knorr's xawtv */
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
|
|
/* 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, " -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);
|
|
}
|