1 #include "config.h"
2 #ifndef HAVE_LIBXV
3 #include "stdio.h"
4 #include "stdlib.h"
main(void)5 int main(void)
6 {puts("Compiled without Xvideo extention support, sorry.");exit(0);}
7 #else
8 /*
9 * put a TV image to the root window - requires Xvideo
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <signal.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #include <X11/StringDefs.h>
23 #include <X11/Xatom.h>
24 #include <X11/extensions/Xv.h>
25 #include <X11/extensions/Xvlib.h>
26
27 #include "vroot.h"
28 #include "atoms.h"
29 #include "parseconfig.h"
30
31 #define SDIMOF(array) ((signed int)(sizeof(array)/sizeof(array[0])))
32
33 int port=-1,bye=0,termsig=0,verbose=0;
34 GC gc;
35
36 XvAdaptorInfo *ai;
37 XvEncodingInfo *ei;
38 XvAttribute *at;
39 XvImageFormatValues *fo;
40
41 static char *reasons[] = {
42 "XvStarted",
43 "XvStopped",
44 "XvBusy",
45 "XvPreempted",
46 "XvHardError",
47 };
48
49 static char *events[] = {
50 "0", "1",
51 "KeyPress",
52 "KeyRelease",
53 "ButtonPress",
54 "ButtonRelease",
55 "MotionNotify",
56 "EnterNotify",
57 "LeaveNotify",
58 "FocusIn",
59 "FocusOut",
60 "KeymapNotify",
61 "Expose",
62 "GraphicsExpose",
63 "NoExpose",
64 "VisibilityNotify",
65 "CreateNotify",
66 "DestroyNotify",
67 "UnmapNotify",
68 "MapNotify",
69 "MapRequest",
70 "ReparentNotify",
71 "ConfigureNotify",
72 "ConfigureRequest",
73 "GravityNotify",
74 "ResizeRequest",
75 "CirculateNotify",
76 "CirculateRequest",
77 "PropertyNotify",
78 "SelectionClear",
79 "SelectionRequest",
80 "SelectionNotify",
81 "ColormapNotify",
82 "ClientMessage",
83 "MappingNotify"
84 };
85
station_list(FILE * fp)86 static void station_list(FILE *fp)
87 {
88 char filename[100];
89 char **list;
90
91 sprintf(filename,"%.*s/%s",(int)sizeof(filename)-8,
92 getenv("HOME"),".xawtv");
93 cfg_parse_file(CONFIGFILE);
94 cfg_parse_file(filename);
95
96 for (list = cfg_list_sections(); *list != NULL; list++) {
97 if (0 == strcmp(*list,"defaults")) continue;
98 if (0 == strcmp(*list,"global")) continue;
99 if (0 == strcmp(*list,"launch")) continue;
100 if (0 == strcmp(*list,"eventmap")) continue;
101 fprintf(fp,"\t\"%s\" EXEC v4lctl setstation \"%s\"\n",
102 *list,*list);
103 }
104 }
105
wm_menu(FILE * fp)106 static void wm_menu(FILE *fp)
107 {
108 fprintf(fp,"\"TV stations\" MENU\n");
109 station_list(fp);
110 fprintf(fp,"\"TV stations\" END\n");
111 }
112
video_blit(Display * dpy,Window win)113 static void video_blit(Display *dpy, Window win)
114 {
115 XWindowAttributes wts;
116
117 XGetWindowAttributes(dpy, win, &wts);
118 #if 0
119 XClearArea(dpy,win,0,0,0,0,False);
120 XvStopVideo(dpy,port,win);
121 #endif
122 XvPutVideo(dpy,port,win,gc,
123 0,0,wts.width,wts.height,
124 0,0,wts.width,wts.height);
125 if (verbose)
126 fprintf(stderr,"XvPutVideo(win=0x%lx,w=%d,h=%d)\n",
127 win,wts.width,wts.height);
128 }
129
130 static void
catch_sig(int signal)131 catch_sig(int signal)
132 {
133 termsig = signal;
134 if (verbose)
135 fprintf(stderr,"received signal %d [%s]\n",
136 termsig,sys_siglist[termsig]);
137 }
138
usage(FILE * fp)139 static void usage(FILE *fp)
140 {
141 fprintf(fp,
142 "rootv is a simple TV application. Uses and requires Xvideo.\n"
143 "Most settings must be tweaked done using some other tool,\n"
144 "v4lctl for example.\n"
145 "\n"
146 "options:\n"
147 " -help print this text\n"
148 " -verbose be verbose\n"
149 " -root put video onto the root window instead of\n"
150 " creating a new window.\n"
151 " -id <win> put video into the window <win> instead of\n"
152 " creating a new window.\n"
153 " -station <st> tune station <st> (just calls v4lctl)\n"
154 " -no-mute don't toggle mute on start/exit.\n"
155 " -port <n> use Xvideo port <n>.\n"
156 " -bg fork into background.\n"
157 " -wm print WindowMaker menu, to set all stations\n"
158 " listed in ~/.xawtv using v4lctl.\n"
159 "\n");
160 }
161
162 int
main(int argc,char * argv[])163 main(int argc, char *argv[])
164 {
165 struct sigaction act,old;
166 Display *dpy;
167 Screen *scr;
168 Window win = -1;
169 XWindowAttributes wts;
170 KeySym keysym;
171 char c;
172
173 int ver, rel, req, ev, err, dummy;
174 int adaptors,attributes;
175 int i,bg,newwin,do_mute,have_mute,grab;
176
177 dpy = XOpenDisplay(NULL);
178 scr = DefaultScreenOfDisplay(dpy);
179 init_atoms(dpy);
180
181 bg = 0;
182 do_mute = 1;
183 have_mute = 0;
184 newwin = 1;
185
186 while (argc > 1) {
187 if (0 == strcmp(argv[1],"-wm")) {
188 /* windowmaker menu */
189 wm_menu(stdout);
190 exit(0);
191 }
192 if (0 == strcmp(argv[1],"-h") ||
193 0 == strcmp(argv[1],"-help") ||
194 0 == strcmp(argv[1],"--help")) {
195 usage(stdout);
196 exit(0);
197 }
198 if (argc > 2 && (0 == strcmp(argv[1],"-id") ||
199 0 == strcmp(argv[1],"-window-id"))) {
200 sscanf(argv[2],"%li",&win);
201 newwin = 0;
202 if (verbose)
203 fprintf(stderr,"using window id 0x%lx\n",win);
204 argc-=2;
205 argv+=2;
206 } else if (argc > 2 && 0 == strcmp(argv[1],"-port")) {
207 sscanf(argv[2],"%i",&port);
208 argc-=2;
209 argv+=2;
210 } else if (argc > 2 && 0 == strcmp(argv[1],"-station")) {
211 if (0 == fork()) {
212 execlp("v4lctl","v4lctl","setstation",argv[2],NULL);
213 exit(1);
214 } else {
215 wait(&dummy);
216 }
217 argc-=2;
218 argv+=2;
219 } else if (0 == strcmp(argv[1],"-root")) {
220 win = RootWindowOfScreen(scr);
221 newwin = 0;
222 if (verbose)
223 fprintf(stderr,"using root window [0x%lx]\n",win);
224 argc--;
225 argv++;
226 } else if (0 == strcmp(argv[1],"-bg")) {
227 bg = 1;
228 argc--;
229 argv++;
230 } else if (0 == strcmp(argv[1],"-verbose")) {
231 verbose = 1;
232 argc--;
233 argv++;
234 } else if (0 == strcmp(argv[1],"-no-mute")) {
235 do_mute = 0;
236 argc--;
237 argv++;
238 } else {
239 fprintf(stderr,"unknown arg: \"%s\"\n",argv[1]);
240 exit(1);
241 }
242 }
243
244 /* init X11 */
245 if (newwin) {
246 win = XCreateSimpleWindow(dpy,RootWindowOfScreen(scr),
247 0,0,640,480,1,
248 BlackPixelOfScreen(scr),
249 BlackPixelOfScreen(scr));
250 XChangeProperty(dpy, win, WM_PROTOCOLS, XA_ATOM, 32,
251 PropModeReplace,
252 (unsigned char *) &WM_DELETE_WINDOW, 1);
253 }
254 XGetWindowAttributes (dpy, win, &wts);
255 XSelectInput(dpy, win, wts.your_event_mask |
256 KeyPressMask | StructureNotifyMask | ExposureMask);
257
258 /* query+print Xvideo properties */
259 if (Success != XvQueryExtension(dpy,&ver,&rel,&req,&ev,&err)) {
260 puts("Server does'nt support Xvideo");
261 exit(1);
262 }
263 if (Success != XvQueryAdaptors(dpy,DefaultRootWindow(dpy),&adaptors,&ai)) {
264 puts("Oops: XvQueryAdaptors failed");
265 exit(1);
266 }
267 if (verbose)
268 fprintf(stderr,"%d adaptors available.\n",adaptors);
269 for (i = 0; i < adaptors; i++) {
270 if (verbose)
271 fprintf(stderr," port=%ld name=\"%s\"\n",ai[i].base_id,ai[i].name);
272
273 /* video adaptor ? */
274 if ((ai[i].type & XvInputMask) &&
275 (ai[i].type & XvVideoMask) &&
276 (port == -1)) {
277 port = ai[i].base_id;
278 }
279 }
280 if (adaptors > 0)
281 XvFreeAdaptorInfo(ai);
282 if (-1 == port) {
283 fprintf(stderr,"no Xvideo port found\n");
284 exit(1);
285 }
286
287 /* grab Xvideo port */
288 grab = 0;
289 for (i = 0; !grab && i < 3; i++) {
290 switch (XvGrabPort(dpy,port,CurrentTime)) {
291 case Success:
292 if (verbose)
293 fprintf(stderr,"grabbed Xv port\n");
294 grab=1;
295 break;
296 case XvAlreadyGrabbed:
297 if (verbose)
298 fprintf(stderr,"Xv port already grabbed\n");
299 sleep(1);
300 break;
301 default:
302 fprintf(stderr,"Xv port grab: Huh?\n");
303 exit(1);
304 }
305 }
306 if (!grab) {
307 fprintf(stderr,"can't grab Xv port\n");
308 exit(1);
309 }
310
311 at = XvQueryPortAttributes(dpy,port,&attributes);
312 for (i = 0; i < attributes; i++) {
313 if (0 == strcmp("XV_MUTE",at[i].name))
314 have_mute = 1;
315 }
316 gc = XCreateGC(dpy,win,0,NULL);
317
318 /* fork into background, but keep tty */
319 if (bg)
320 if (fork())
321 exit(0);
322
323 /* catch signals */
324 memset(&act,0,sizeof(act));
325 sigemptyset(&act.sa_mask);
326 act.sa_handler = catch_sig;
327 sigaction(SIGINT,&act,&old);
328 sigaction(SIGHUP,&act,&old);
329 sigaction(SIGTERM,&act,&old);
330
331 /* put video to the window */
332 if (newwin)
333 XMapWindow(dpy,win);
334 if (verbose)
335 fprintf(stderr,"starting video\n");
336 video_blit(dpy,win);
337 if (do_mute && have_mute)
338 XvSetPortAttribute(dpy,port,XV_MUTE,0);
339
340 /* receive events */
341 XvSelectPortNotify(dpy, port, 1);
342 XvSelectVideoNotify(dpy, win, 1);
343
344 /* main loop */
345 for (;!bye && !termsig;) {
346 int rc;
347 fd_set set;
348 XEvent event;
349
350 if (False == XCheckMaskEvent(dpy, ~0, &event)) {
351 /* wait for x11 events, make sure that signals are catched */
352 XFlush(dpy);
353 FD_ZERO(&set);
354 FD_SET(ConnectionNumber(dpy),&set);
355 rc = select(ConnectionNumber(dpy)+1,&set,NULL,NULL,NULL);
356 if (-1 == rc)
357 if (verbose)
358 perror("... select");
359 continue;
360 }
361
362 if (event.type > ev) {
363 /* Xvideo extention event */
364 switch (event.type-ev) {
365 case XvVideoNotify:
366 {
367 XvVideoNotifyEvent *xve = (XvVideoNotifyEvent*)&event;
368 if (verbose)
369 fprintf(stderr,"XvVideoNotify, reason=%s, exiting\n",
370 reasons[xve->reason]);
371 #if 0
372 bye=1;
373 #endif
374 break;
375 }
376 case XvPortNotify:
377 {
378 XvPortNotifyEvent *xpe = (XvPortNotifyEvent*)&event;
379 if (verbose)
380 fprintf(stderr,"XvPortNotify: %s=%ld\n",
381 XGetAtomName(dpy,xpe->attribute),xpe->value);
382 break;
383 }
384 }
385 } else {
386 /* other event */
387 switch (event.type) {
388 case KeyPress:
389 c = 0;
390 XLookupString (&event.xkey, &c, 1, &keysym, 0);
391 if (verbose)
392 fprintf(stderr,"key: %c\n",c);
393 switch (c) {
394 case 'q':
395 case 'Q':
396 case 3: /* ^C */
397 case 27: /* ESC */
398 bye = 1;
399 }
400 break;
401 case ClientMessage:
402 if (event.xclient.message_type == WM_PROTOCOLS &&
403 (Atom)event.xclient.data.l[0] == WM_DELETE_WINDOW)
404 bye = 1;
405 break;
406 case Expose:
407 if (event.xexpose.count)
408 break;
409 /* fall througth */
410 case ConfigureNotify:
411 video_blit(dpy,win);
412 break;
413 default:
414 if (verbose) {
415 if (event.type < SDIMOF(events))
416 fprintf(stderr,"ev: %s\n",events[event.type]);
417 else
418 fprintf(stderr,"ev: #%d\n",event.type);
419 }
420 }
421 }
422 }
423 if (verbose && termsig)
424 fprintf(stderr,"exiting on signal %d [%s]\n",
425 termsig,sys_siglist[termsig]);
426 if (do_mute && have_mute)
427 XvSetPortAttribute(dpy,port,XV_MUTE,1);
428 XvStopVideo(dpy,port,win);
429 XvUngrabPort(dpy,port,CurrentTime);
430 XClearArea(dpy,win,0,0,0,0,True);
431 XCloseDisplay(dpy);
432 if (verbose)
433 fprintf(stderr,"bye\n");
434
435 /* keep compiler happy */
436 exit(0);
437 }
438
439 #endif
440