Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * main.c for xawtv -- a TV application
  3  *
  4  *   (c) 1997-2002 Gerd Knorr <kraxel@bytesex.org>
  5  *
  6  */
  7 
  8 #define _GNU_SOURCE
  9 
 10 #include "config.h"
 11 
 12 #include <stdio.h>
 13 #include <stdlib.h>
 14 #include <unistd.h>
 15 #include <string.h>
 16 #include <ctype.h>
 17 #include <errno.h>
 18 #include <math.h>
 19 #include <signal.h>
 20 #include <fcntl.h>
 21 #include <pthread.h>
 22 #include <sys/time.h>
 23 #include <sys/socket.h>
 24 #include <sys/wait.h>
 25 #include <sys/stat.h>
 26 #include <netinet/in.h>
 27 #include <arpa/inet.h>
 28 
 29 #include <X11/Xlib.h>
 30 #include <X11/Xutil.h>
 31 #include <X11/Xproto.h>
 32 #include <X11/Xmd.h>
 33 #include <X11/Intrinsic.h>
 34 #include <X11/StringDefs.h>
 35 #include <X11/Xatom.h>
 36 #include <X11/Shell.h>
 37 #include <X11/Xaw/XawInit.h>
 38 #include <X11/Xaw/Paned.h>
 39 #include <X11/Xaw/Command.h>
 40 #include <X11/Xaw/Scrollbar.h>
 41 #include <X11/Xaw/Viewport.h>
 42 #include <X11/Xaw/Box.h>
 43 #include <X11/Xaw/Dialog.h>
 44 #include <X11/Xaw/AsciiText.h>
 45 #include <X11/extensions/XShm.h>
 46 
 47 #include "grab-ng.h"
 48 #include "writefile.h"
 49 
 50 #include "sound.h"
 51 #include "channel.h"
 52 #include "commands.h"
 53 #include "frequencies.h"
 54 #include "xv.h"
 55 #include "capture.h"
 56 #include "atoms.h"
 57 #include "xt.h"
 58 #include "x11.h"
 59 #include "toolbox.h"
 60 #include "complete.h"
 61 #include "wmhooks.h"
 62 #include "conf.h"
 63 #include "blit.h"
 64 #include "vbi-data.h"
 65 #include "vbi-x11.h"
 66 
 67 #define LABEL_WIDTH         "16"
 68 #define BOOL_WIDTH          "24"
 69 
 70 /*--- public variables ----------------------------------------------------*/
 71 
 72 static String fallback_ressources[] = {
 73 #include "Xawtv.h"
 74     NULL
 75 };
 76 
 77 Widget            opt_shell, opt_paned, chan_shell, conf_shell, str_shell;
 78 Widget            launch_shell, launch_paned;
 79 Widget            c_freq,c_cap;
 80 Widget            s_bright,s_color,s_hue,s_contrast,s_volume;
 81 Widget            chan_viewport, chan_box;
 82 Pixmap            tv_pix;
 83 struct vbi_window *vtx;
 84 
 85 int               have_config = 0;
 86 XtIntervalId      audio_timer;
 87 int               debug = 0;
 88 
 89 char              modename[64];
 90 char              *progname;
 91 
 92 XtWorkProcId      rec_work_id;
 93 
 94 /* movie params / setup */
 95 Widget            w_movie_status;
 96 Widget            w_movie_driver;
 97 
 98 Widget            w_movie_fvideo;
 99 Widget            w_movie_video;
100 Widget            w_movie_fps;
101 Widget            w_movie_size;
102 
103 Widget            w_movie_flabel;
104 Widget            w_movie_faudio;
105 Widget            w_movie_audio;
106 Widget            w_movie_rate;
107 
108 struct STRTAB     *m_movie_driver;
109 struct STRTAB     *m_movie_audio;
110 struct STRTAB     *m_movie_video;
111 
112 struct ng_writer  *movie_driver  = NULL;
113 unsigned int      i_movie_driver = 0;
114 unsigned int      movie_audio    = 0;
115 unsigned int      movie_video    = 0;
116 unsigned int      movie_fps      = 12000;
117 unsigned int      movie_rate     = 44100;
118 
119 static struct STRTAB m_movie_fps[] = {
120     {  2000, " 2.0   fps" },
121     {  3000, " 3.0   fps" },
122     {  5000, " 5.0   fps" },
123     {  8000, " 8.0   fps" },
124     { 10000, "10.0   fps" },
125     { 12000, "12.0   fps" },
126     { 15000, "15.0   fps" },
127     { 18000, "18.0   fps" },
128     { 20000, "20.0   fps" },
129     { 23976, "23.976 fps" },
130     { 24000, "24.0   fps" },
131     { 25000, "25.0   fps" },
132     { 29970, "29.970 fps" },
133     { 30000, "30.0   fps" },
134     { -1, NULL },
135 };
136 static struct STRTAB m_movie_rate[] = {
137     {   8000, " 8000" },
138     {  11025, "11025" },
139     {  22050, "22050" },
140     {  44100, "44100" },
141     {  48000, "48000" },
142     { -1, NULL },
143 };
144 
145 struct xaw_attribute {
146     struct ng_attribute   *attr;
147     Widget                cmd,scroll;
148     struct xaw_attribute  *next;
149 };
150 static struct xaw_attribute *xaw_attrs;
151 
152 #define MOVIE_DRIVER  "movie driver"
153 #define MOVIE_AUDIO   "audio format"
154 #define MOVIE_VIDEO   "video format"
155 #define MOVIE_FPS     "frames/sec"
156 #define MOVIE_RATE    "sample rate"
157 #define MOVIE_SIZE    "video size"
158 
159 /* fwd decl */
160 void change_audio(int mode);
161 void watch_audio(XtPointer data, XtIntervalId *id);
162 
163 /*-------------------------------------------------------------------------*/
164 
165 static struct MY_TOPLEVELS {
166     char        *name;
167     Widget      *shell;
168     int         *check;
169     int          first;
170     int          mapped;
171 } my_toplevels [] = {
172     { "options",  &opt_shell              },
173     { "channels", &chan_shell,   &count   },
174     { "config",   &conf_shell,            },
175     { "streamer", &str_shell              },
176     { "launcher", &launch_shell, &nlaunch }
177 };
178 #define TOPLEVELS (sizeof(my_toplevels)/sizeof(struct MY_TOPLEVELS))
179 
180 struct STRTAB *cmenu = NULL;
181 
182 struct DO_AC {
183     int  argc;
184     char *name;
185     char *argv[8];
186 };
187 
188 /*--- actions -------------------------------------------------------------*/
189 
190 /* conf.c */
191 extern void create_confwin(void);
192 extern void conf_station_switched(void);
193 extern void conf_list_update(void);
194 
195 void CloseMainAction(Widget, XEvent*, String*, Cardinal*);
196 void ScanAction(Widget, XEvent*, String*, Cardinal*);
197 void ChannelAction(Widget, XEvent*, String*, Cardinal*);
198 void StayOnTop(Widget, XEvent*, String*, Cardinal*);
199 void PopupAction(Widget, XEvent*, String*, Cardinal*);
200 
201 static XtActionsRec actionTable[] = {
202     { "CloseMain",   CloseMainAction  },
203     { "Scan",        ScanAction },
204     { "Channel",     ChannelAction },
205     { "Remote",      RemoteAction },
206     { "Zap",         ZapAction },
207     { "Complete",    CompleteAction },
208     { "Help",        help_AC },
209     { "StayOnTop",   StayOnTop },
210     { "Launch",      LaunchAction },
211     { "Popup",       PopupAction },
212     { "Command",     CommandAction },
213     { "Autoscroll",  offscreen_scroll_AC },
214     { "Ratio",       RatioAction },
215 #ifdef HAVE_ZVBI
216     { "Vtx",         VtxAction },
217 #endif
218     { "Event",       EventAction },
219 };
220 
221 static struct STRTAB cap_list[] = {
222     {  CAPTURE_OFF,         "off"         },
223     {  CAPTURE_OVERLAY,     "overlay"     },
224     {  CAPTURE_GRABDISPLAY, "grabdisplay" },
225     {  -1, NULL,     },
226 };
227 
228 /*--- exit ----------------------------------------------------------------*/
229 
230 void
231 PopupAction(Widget widget, XEvent *event,
232             String *params, Cardinal *num_params)
233 {
234     Dimension h;
235     unsigned int i;
236     int mh;
237 
238     /* which window we are talking about ? */
239     if (*num_params > 0) {
240         for (i = 0; i < TOPLEVELS; i++) {
241             if (0 == strcasecmp(my_toplevels[i].name,params[0]))
242                 break;
243         }
244     } else {
245         for (i = 0; i < TOPLEVELS; i++) {
246             if (*(my_toplevels[i].shell) == widget)
247                 break;
248         }
249     }
250     if (i == TOPLEVELS) {
251         fprintf(stderr,"PopupAction: oops: shell widget not found (%s)\n",
252                 (*num_params > 0) ? params[0] : "-");
253         return;
254     }
255 
256     /* Message from WM ??? */
257     if (NULL != event && event->type == ClientMessage) {
258         if (debug)
259             fprintf(stderr,"%s: received %s message\n",
260                     my_toplevels[i].name,
261                     XGetAtomName(dpy,event->xclient.data.l[0]));
262         if ((Atom)event->xclient.data.l[0] == WM_DELETE_WINDOW) {
263             /* fall throuth -- popdown window */
264         } else {
265             /* whats this ?? */
266             return;
267         }
268     }
269 
270     /* check if window should be displayed */
271     if (NULL != my_toplevels[i].check)
272         if (0 == *(my_toplevels[i].check))
273             return;
274 
275     /* popup/down window */
276     if (my_toplevels[i].mapped) {
277         XtPopdown(*(my_toplevels[i].shell));
278         my_toplevels[i].mapped = 0;
279     } else {
280         XtPopup(*(my_toplevels[i].shell), XtGrabNone);
281         if (wm_stay_on_top && stay_on_top > 0)
282             wm_stay_on_top(dpy,XtWindow(*(my_toplevels[i].shell)),1);
283         my_toplevels[i].mapped = 1;
284         if (!my_toplevels[i].first) {
285             XSetWMProtocols(XtDisplay(*(my_toplevels[i].shell)),
286                             XtWindow(*(my_toplevels[i].shell)),
287                             &WM_DELETE_WINDOW, 1);
288             mh = h = 0;
289             XtVaGetValues(*(my_toplevels[i].shell),
290                           XtNmaxHeight,&mh,
291                           XtNheight,&h,
292                           NULL);
293             if (mh > 0 && h > mh) {
294                 if (debug)
295                     fprintf(stderr,"height fixup: %d => %d\n",h,mh);
296                 XtVaSetValues(*(my_toplevels[i].shell),XtNheight,mh,NULL);
297             }
298             my_toplevels[i].first = 1;
299         }
300     }
301 }
302 
303 static void
304 action_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
305 {
306     struct DO_AC *ca = clientdata;
307     XtCallActionProc(widget,ca->name,NULL,ca->argv,ca->argc);
308 }
309 
310 void toolkit_set_label(Widget widget, char *str)
311 {
312     XtVaSetValues(widget,XtNlabel,str,NULL);    
313 }
314 
315 /*--- videotext ----------------------------------------------------------*/
316 
317 static void create_vtx(void)
318 {
319     Widget shell,label;
320 
321     shell = XtVaCreateWidget("vtx",transientShellWidgetClass,
322                              app_shell,
323                              XtNoverrideRedirect,True,
324                              XtNvisual,vinfo.visual,
325                              XtNcolormap,colormap,
326                              XtNdepth,vinfo.depth,
327                              NULL);
328     label = XtVaCreateManagedWidget("label", labelWidgetClass, shell,
329                                     NULL);
330 #ifdef HAVE_ZVBI
331     vtx = vbi_render_init(shell,label,NULL);
332 #endif
333 }
334 
335 #if TT
336 static void
337 display_vtx(struct TEXTELEM *tt)
338 {
339     static Pixel fg, bg;
340     static XFontStruct *font;
341     static Pixmap pix;
342     static GC gc;
343     static int first = 1;
344     XColor color, dummy;
345     XGCValues  values;
346     Dimension x,y,w,h,sw,sh;
347     int maxwidth,width,height,direction,ascent,descent,lastline,i;
348     XCharStruct cs;
349 
350     if (NULL == tt) {
351         XtPopdown(vtx_shell);
352         return;
353     }
354 
355     if (NULL == font) {
356         XtVaGetValues(vtx_label,
357                       XtNfont,&font,
358                       XtNbackground,&bg,
359                       XtNforeground,&fg,
360                       NULL);
361         values.font = font->fid;
362         gc = XCreateGC(dpy, XtWindow(vtx_label), GCFont, &values);
363     }
364 
365     /* calc size + positions */
366     width = 0; height = 0; maxwidth = 0;
367     lastline = -1;
368     for (i = 0; tt[i].len; i++) {
369         XTextExtents(font,tt[i].str,tt[i].len,
370                      &direction,&ascent,&descent,&cs);
371         if (lastline != tt[i].line) {
372             if (maxwidth < width)
373                 maxwidth = width;
374             width = 0;
375             height += ascent+descent;
376             lastline = tt[i].line;
377         }
378         tt[i].x = width;
379         tt[i].y = height - descent;
380         width += cs.width;
381     }
382     if (maxwidth < width)
383         maxwidth = width;
384 
385     /* alloc pixmap + draw text */
386     if (pix)
387         XFreePixmap(dpy,pix);
388     fprintf(stderr,"pix: %dx%d\n",maxwidth, height);
389     pix = XCreatePixmap(dpy, RootWindowOfScreen(XtScreen(vtx_label)),
390                         maxwidth, height,
391                         DefaultDepthOfScreen(XtScreen(vtx_label)));
392     values.foreground = bg;
393     values.background = bg;
394     XChangeGC(dpy, gc, GCForeground | GCBackground, &values);
395     XFillRectangle(dpy,pix,gc,0,0,maxwidth,height);
396     for (i = 0; tt[i].len; i++) {
397         if (tt[i].fg) {
398             XAllocNamedColor(dpy,colormap,tt[i].fg,
399                              &color,&dummy);
400             values.foreground = color.pixel;
401         } else {
402             values.foreground = fg;
403         }
404         if (tt[i].bg) {
405             XAllocNamedColor(dpy,colormap,tt[i].bg,
406                              &color,&dummy);
407             values.background = color.pixel;
408         } else {
409             values.background = bg;
410         }
411         XChangeGC(dpy, gc, GCForeground | GCBackground, &values);
412         XDrawImageString(dpy,pix,gc,tt[i].x,tt[i].y,tt[i].str,tt[i].len);
413     }
414     XtVaSetValues(vtx_label,XtNbitmap,pix,XtNlabel,NULL,NULL);
415 
416     XtVaGetValues(app_shell,XtNx,&x,XtNy,&y,XtNwidth,&w,XtNheight,&h,NULL);
417     XtVaGetValues(vtx_shell,XtNwidth,&sw,XtNheight,&sh,NULL);
418     XtVaSetValues(vtx_shell,XtNx,x+(w-sw)/2,XtNy,y+h-10-sh,NULL);
419     XtPopup(vtx_shell, XtGrabNone);
420     if (wm_stay_on_top && stay_on_top > 0)
421         wm_stay_on_top(dpy,XtWindow(vtx_shell),1);
422 
423     if (first) {
424         first = 0;
425         XDefineCursor(dpy, XtWindow(vtx_shell), left_ptr);
426         XDefineCursor(dpy, XtWindow(vtx_label), left_ptr);
427     }
428 }
429 #endif
430 
431 #ifdef HAVE_ZVBI
432 static void
433 display_subtitle(struct vbi_page *pg, struct vbi_rect *rect)
434 {
435     static int first = 1;
436     static Pixmap pix;
437     Dimension x,y,w,h,sw,sh;
438 
439     if (NULL == pg) {
440         XtPopdown(vtx->shell);
441         return;
442     }
443 
444     if (pix)
445         XFreePixmap(dpy,pix);
446     pix = vbi_export_pixmap(vtx,pg,rect);
447     XtVaSetValues(vtx->tt,XtNbitmap,pix,XtNlabel,NULL,NULL);
448 
449     XtVaGetValues(app_shell,XtNx,&x,XtNy,&y,XtNwidth,&w,XtNheight,&h,NULL);
450     XtVaGetValues(vtx->shell,XtNwidth,&sw,XtNheight,&sh,NULL);
451     XtVaSetValues(vtx->shell,XtNx,x+(w-sw)/2,XtNy,y+h-10-sh,NULL);
452     XtPopup(vtx->shell, XtGrabNone);
453     if (wm_stay_on_top && stay_on_top > 0)
454         wm_stay_on_top(dpy,XtWindow(vtx->shell),1);
455 
456     if (first) {
457         first = 0;
458         XDefineCursor(dpy, XtWindow(vtx->shell), left_ptr);
459         XDefineCursor(dpy, XtWindow(vtx->tt), left_ptr);
460     }
461 }
462 #endif
463 
464 /*--- tv -----------------------------------------------------------------*/
465 
466 static void
467 resize_event(Widget widget, XtPointer client_data, XEvent *event, Boolean *d)
468 {
469     static int width = 0, height = 0, first = 1;
470     char label[64];
471     
472     switch(event->type) {
473     case ConfigureNotify:
474         if (first) {
475             video_gd_init(tv,args.gl);
476             first = 0;
477         }
478         if (width  != event->xconfigure.width ||
479             height != event->xconfigure.height) {
480             width  = event->xconfigure.width;
481             height = event->xconfigure.height;
482             video_gd_configure(width, height);
483             XClearWindow(XtDisplay(tv),XtWindow(tv));
484             sprintf(label,"%-" LABEL_WIDTH "s: %dx%d",MOVIE_SIZE,width,height);
485             if (w_movie_size)
486                 XtVaSetValues(w_movie_size,XtNlabel,label,NULL);
487         }
488         break;
489     }
490 }
491 
492 /*------------------------------------------------------------------------*/
493 
494 /* the RightWay[tm] to set float resources (copyed from Xaw specs) */
495 static void
496 set_float(Widget widget, char *name, float value)
497 {
498     Arg   args[1];
499 
500     if (sizeof(float) > sizeof(XtArgVal)) {
501         /*
502          * If a float is larger than an XtArgVal then pass this 
503          * resource value by reference.
504          */
505         XtSetArg(args[0], name, &value);
506     } else {
507         /*
508          * Convince C not to perform an automatic conversion, which
509          * would truncate 0.5 to 0.
510          *
511          * switched from pointer tricks to the union to fix alignment
512          * problems on ia64 (Stephane Eranian <eranian@cello.hpl.hp.com>)
513          */
514         union {
515             XtArgVal xt;
516             float   fp;
517         } foo;
518         foo.fp = value;
519         XtSetArg(args[0], name, foo.xt);
520     }
521     XtSetValues(widget,args,1);
522 }
523 
524 static void
525 new_freqtab(void)
526 {
527     char label[64];
528 
529     if (c_freq) {
530         sprintf(label,"%-" LABEL_WIDTH "s: %s","Frequency table",
531                 chanlists[chantab].name);
532         XtVaSetValues(c_freq,XtNlabel,label,NULL);
533     }
534 }
535 
536 static void
537 new_attr(struct ng_attribute *attr, int val)
538 {
539     struct xaw_attribute *a;
540     char label[64],*olabel;
541     const char *valstr;
542 
543     for (a = xaw_attrs; NULL != a; a = a->next) {
544         if (a->attr->id == attr->id)
545             break;
546     }
547     if (NULL != a) {
548         switch (attr->type) {
549         case ATTR_TYPE_CHOICE:
550             XtVaGetValues(a->cmd,XtNlabel,&olabel,NULL);
551             valstr = ng_attr_getstr(attr,val);
552             sprintf(label,"%-" LABEL_WIDTH "." LABEL_WIDTH "s: %s",
553                     olabel,valstr ? valstr : "unknown");
554             XtVaSetValues(a->cmd,XtNlabel,label,NULL);
555             break;
556         case ATTR_TYPE_BOOL:
557             XtVaGetValues(a->cmd,XtNlabel,&olabel,NULL);
558             sprintf(label,"%-" BOOL_WIDTH "." BOOL_WIDTH "s  %s",
559                     olabel,val ? "on" : "off");
560             XtVaSetValues(a->cmd,XtNlabel,label,NULL);
561             break;
562         case ATTR_TYPE_INTEGER:
563             set_float(a->scroll,XtNtopOfThumb,
564                       (float)(val-attr->min) / (attr->max - attr->min));
565             break;
566         }
567         return;
568     }
569 }
570 
571 static void
572 new_volume(void)
573 {
574     struct ng_attribute *attr;
575 
576     attr = ng_attr_byid(attrs,ATTR_ID_VOLUME);
577     if (NULL != attr)
578         new_attr(attr,cur_attrs[ATTR_ID_VOLUME]);
579 }
580 
581 static void
582 new_channel(void)
583 {
584     set_property(cur_freq,
585                  (cur_channel == -1) ? NULL : chanlist[cur_channel].name,
586                  (cur_sender == -1)  ? NULL : channels[cur_sender]->name);
587     conf_station_switched();
588     
589     if (zap_timer) {
590         XtRemoveTimeOut(zap_timer);
591         zap_timer = 0;
592     }
593     if (scan_timer) {
594         XtRemoveTimeOut(scan_timer);
595         scan_timer = 0;
596     }
597     if (audio_timer) {
598         XtRemoveTimeOut(audio_timer);
599         audio_timer = 0;
600     }
601     audio_timer = XtAppAddTimeOut(app_context, 5000, watch_audio, NULL);
602 }
603 
604 void
605 watch_audio(XtPointer data, XtIntervalId *id)
606 {
607     if (-1 != cur_sender)
608         change_audio(channels[cur_sender]->audio);
609     audio_timer = 0;
610 }
611 
612 /*------------------------------------------------------------------------*/
613 
614 static void
615 do_capture(int from, int to, int tmp_switch)
616 {
617     static int niced = 0;
618     char label[64];
619 
620     /* off */
621     switch (from) {
622     case CAPTURE_OFF:
623         XtVaSetValues(tv,XtNbackgroundPixmap,XtUnspecifiedPixmap,NULL);
624         if (tv_pix)
625             XFreePixmap(dpy,tv_pix);
626         tv_pix = 0;
627         break;
628     case CAPTURE_GRABDISPLAY:
629         video_gd_stop();
630         XClearArea(XtDisplay(tv), XtWindow(tv), 0,0,0,0, True);
631         break;
632     case CAPTURE_OVERLAY:
633         video_overlay(0);
634         break;
635     }
636 
637     /* on */
638     switch (to) {
639     case CAPTURE_OFF:
640         sprintf(label,"%-" LABEL_WIDTH "s: %s","Capture","off");
641         if (!tmp_switch) {
642             tv_pix = x11_capture_pixmap(dpy, &vinfo, colormap, 0, 0);
643             if (tv_pix)
644                 XtVaSetValues(tv,XtNbackgroundPixmap,tv_pix,NULL);
645         }
646         break;
647     case CAPTURE_GRABDISPLAY:
648         sprintf(label,"%-" LABEL_WIDTH "s: %s","Capture","grabdisplay");
649         if (!niced)
650             nice(niced = 10);
651         video_gd_start();
652         break;
653     case CAPTURE_OVERLAY:
654         sprintf(label,"%-" LABEL_WIDTH "s: %s","Capture","overlay");
655         video_overlay(1);
656         break;
657     }
658     if (c_cap)
659         XtVaSetValues(c_cap,XtNlabel,label,NULL);
660 }
661 
662 /* gets called before switching away from a channel */
663 static void
664 pixit(void)
665 {
666     Pixmap pix;
667     struct ng_video_fmt fmt;
668     struct ng_video_buf *buf;
669 
670     if (cur_sender == -1)
671         return;
672 
673     /* save picture settings */
674     channels[cur_sender]->color    = cur_attrs[ATTR_ID_COLOR];
675     channels[cur_sender]->bright   = cur_attrs[ATTR_ID_BRIGHT];
676     channels[cur_sender]->hue      = cur_attrs[ATTR_ID_HUE];
677     channels[cur_sender]->contrast = cur_attrs[ATTR_ID_CONTRAST];
678     channels[cur_sender]->input    = cur_attrs[ATTR_ID_INPUT];
679     channels[cur_sender]->norm     = cur_attrs[ATTR_ID_NORM];
680 
681     if (0 == pix_width || 0 == pix_height)
682         return;
683 
684     /* capture mini picture */
685     if (!(f_drv & CAN_CAPTURE))
686         return;
687 
688     video_gd_suspend();
689     memset(&fmt,0,sizeof(fmt));
690     fmt.fmtid  = x11_dpy_fmtid;
691     fmt.width  = pix_width;
692     fmt.height = pix_height;
693     if (NULL == (buf = ng_grabber_get_image(&fmt)))
694         goto done1;
695     buf = ng_filter_single(cur_filter,buf);
696     if (0 == (pix = x11_create_pixmap(dpy,&vinfo,buf)))
697         goto done2;
698     x11_label_pixmap(dpy,colormap,pix,buf->fmt.height,
699                      channels[cur_sender]->name);
700     XtVaSetValues(channels[cur_sender]->button,
701                   XtNbackgroundPixmap,pix,
702                   XtNlabel,"",
703                   XtNwidth,pix_width,
704                   XtNheight,pix_height,
705                   NULL);
706     if (channels[cur_sender]->pixmap)
707         XFreePixmap(dpy,channels[cur_sender]->pixmap);
708     channels[cur_sender]->pixmap = pix;
709     
710  done2:
711     ng_release_video_buf(buf);
712  done1:
713     video_gd_restart();
714 }
715 
716 static void
717 set_menu_val(Widget widget, char *name, struct STRTAB *tab, int val)
718 {
719     char label[64];
720     int i;
721 
722     for (i = 0; tab[i].str != NULL; i++) {
723         if (tab[i].nr == val)
724             break;
725     }
726     sprintf(label,"%-15s : %s",name,
727             (tab[i].str != NULL) ? tab[i].str : "invalid");
728     XtVaSetValues(widget,XtNlabel,label,NULL);
729 }
730 
731 void
732 ChannelAction(Widget widget, XEvent *event,
733               String *params, Cardinal *num_params)
734 {
735     int i;
736 
737     if (0 == count)
738         return;
739     i = popup_menu(widget,"Stations",cmenu);
740 
741     if (i != -1)
742         do_va_cmd(2,"setstation",channels[i]->name);
743 }
744 
745 static void create_chanwin(void)
746 {
747     chan_shell = XtVaAppCreateShell("Channels", "Xawtv",
748                                     topLevelShellWidgetClass,
749                                     dpy,
750                                     XtNclientLeader,app_shell,
751                                     XtNvisual,vinfo.visual,
752                                     XtNcolormap,colormap,
753                                     XtNdepth,vinfo.depth,
754                       XtNheight,XtScreen(app_shell)->height/2,
755                       XtNmaxHeight,XtScreen(app_shell)->height-50,
756                                     NULL);
757     XtOverrideTranslations(chan_shell, XtParseTranslationTable
758                            ("<Message>WM_PROTOCOLS: Popup()"));
759     chan_viewport = XtVaCreateManagedWidget("viewport",
760                                             viewportWidgetClass, chan_shell,
761                                             XtNallowHoriz, False,
762                                             XtNallowVert, True,
763                                             NULL);
764     chan_box = XtVaCreateManagedWidget("channelbox",
765                                        boxWidgetClass, chan_viewport,
766                                        XtNsensitive, True,
767                                        NULL);
768 }
769 
770 void channel_menu(void); /* FIXME */
771 void channel_menu(void)
772 {
773     int  i,max,len;
774     char str[100];
775 
776     if (cmenu)
777         free(cmenu);
778     cmenu = malloc((count+1)*sizeof(struct STRTAB));
779     memset(cmenu,0,(count+1)*sizeof(struct STRTAB));
780     for (i = 0, max = 0; i < count; i++) {
781         len = strlen(channels[i]->name);
782         if (max < len)
783             max = len;
784     }
785     for (i = 0; i < count; i++) {
786         cmenu[i].nr      = i;
787         cmenu[i].str     = channels[i]->name;
788         if (channels[i]->key) {
789             sprintf(str,"%2d  %-*s  %s",i+1,
790                     max+2,channels[i]->name,channels[i]->key);
791         } else {
792             sprintf(str,"%2d  %-*s",i+1,max+2,channels[i]->name);
793         }
794         cmenu[i].str=strdup(str);
795     }
796     conf_list_update();
797     calc_frequencies();
798 }
799 
800 void
801 StayOnTop(Widget widget, XEvent *event,
802           String *params, Cardinal *num_params)
803 {
804     unsigned int i;
805 
806     if (!wm_stay_on_top)
807         return;
808 
809     stay_on_top = stay_on_top ? 0 : 1;
810     if (debug)
811         fprintf(stderr,"stay_on_top: %d\n",stay_on_top);
812         
813     wm_stay_on_top(dpy,XtWindow(app_shell),stay_on_top);
814     wm_stay_on_top(dpy,XtWindow(on_shell),stay_on_top);
815     for (i = 0; i < TOPLEVELS; i++)
816         wm_stay_on_top(dpy,XtWindow(*(my_toplevels[i].shell)),
817                        (stay_on_top == -1) ? 0 : stay_on_top);
818 }
819 
820 /*--- option window ------------------------------------------------------*/
821 
822 static void
823 update_movie_menus(void)
824 {
825     struct list_head *item;
826     struct ng_writer *writer;
827     Boolean sensitive;
828     unsigned int i;
829 
830     /* drivers  */
831     if (NULL == m_movie_driver) {
832         i = 0;
833         list_for_each(item,&ng_writers)
834             i++;
835         m_movie_driver = malloc(sizeof(struct STRTAB)*(i+1));
836         memset(m_movie_driver,0,sizeof(struct STRTAB)*(i+1));
837         i = 0;
838         list_for_each(item,&ng_writers) {
839             writer = list_entry(item, struct ng_writer, list);
840             m_movie_driver[i].nr  = i;
841             m_movie_driver[i].str = writer->desc;
842             if (NULL == movie_driver ||
843                 (NULL != mov_driver && 0 == strcasecmp(mov_driver,writer->name))) {
844                 movie_driver = writer;
845                 i_movie_driver = i;
846             }
847             i++;
848         }
849         m_movie_driver[i].nr  = i;
850         m_movie_driver[i].str = NULL;
851     }
852 
853     /* audio formats */
854     for (i = 0; NULL != movie_driver->audio[i].name; i++)
855         ;
856     if (m_movie_audio)
857         free(m_movie_audio);
858     movie_audio = 0;
859     m_movie_audio = malloc(sizeof(struct STRTAB)*(i+2));
860     memset(m_movie_audio,0,sizeof(struct STRTAB)*(i+2));
861     for (i = 0; NULL != movie_driver->audio[i].name; i++) {
862         m_movie_audio[i].nr  = i;
863         m_movie_audio[i].str = movie_driver->audio[i].desc ?
864             movie_driver->audio[i].desc : 
865             ng_afmt_to_desc[movie_driver->audio[i].fmtid];
866         if (NULL != mov_audio)
867             if (0 == strcasecmp(mov_audio,movie_driver->audio[i].name))
868                 movie_audio = i;
869     }
870     m_movie_audio[i].nr  = i;
871     m_movie_audio[i].str = "no sound";
872 
873     /* video formats */
874     for (i = 0; NULL != movie_driver->video[i].name; i++)
875         ;
876     if (m_movie_video)
877         free(m_movie_video);
878     movie_video = 0;
879     m_movie_video = malloc(sizeof(struct STRTAB)*(i+2));
880     memset(m_movie_video,0,sizeof(struct STRTAB)*(i+2));
881     for (i = 0; NULL != movie_driver->video[i].name; i++) {
882         m_movie_video[i].nr  = i;
883         m_movie_video[i].str = movie_driver->video[i].desc ?
884             movie_driver->video[i].desc : 
885             ng_vfmt_to_desc[movie_driver->video[i].fmtid];
886         if (NULL != mov_video)
887             if (0 == strcasecmp(mov_video,movie_driver->video[i].name))
888                 movie_video = i;
889     }
890 
891     /* need audio filename? */
892     sensitive = movie_driver->combined ? False : True;
893     XtVaSetValues(w_movie_flabel,
894                   XtNsensitive,sensitive,
895                   NULL);
896     XtVaSetValues(w_movie_faudio,
897                   XtNsensitive,sensitive,
898                   NULL);
899 }
900 
901 static void
902 init_movie_menus(void)
903 {
904     update_movie_menus();
905 
906     if (mov_rate)
907         do_va_cmd(3,"movie","rate",mov_rate);
908     if (mov_fps)
909         do_va_cmd(3,"movie","fps",mov_fps);
910     set_menu_val(w_movie_driver,MOVIE_DRIVER,m_movie_driver,i_movie_driver);
911     set_menu_val(w_movie_audio,MOVIE_AUDIO,m_movie_audio,movie_audio);
912     set_menu_val(w_movie_rate,MOVIE_RATE,m_movie_rate,movie_rate);
913     set_menu_val(w_movie_video,MOVIE_VIDEO,m_movie_video,movie_video);
914     set_menu_val(w_movie_fps,MOVIE_FPS,m_movie_fps,movie_fps);
915 }
916 
917 #define PANED_FIX               \
918         XtNallowResize, False,  \
919         XtNshowGrip,    False,  \
920         XtNskipAdjust,  True
921 
922 struct DO_CMD cmd_fs   = { 1, { "fullscreen",        NULL }};
923 struct DO_CMD cmd_mute = { 2, { "volume",  "mute",   NULL }};
924 struct DO_CMD cmd_cap  = { 2, { "capture", "toggle", NULL }};
925 struct DO_CMD cmd_jpeg = { 2, { "snap",    "jpeg",   NULL }};
926 struct DO_CMD cmd_ppm  = { 2, { "snap",    "ppm",    NULL }};
927 
928 struct DO_AC  ac_fs    = { 0, "FullScreen", { NULL }};
929 struct DO_AC  ac_top   = { 0, "StayOnTop",  { NULL }};
930 
931 struct DO_AC  ac_avi   = { 1, "Popup",      { "streamer", NULL }};
932 struct DO_AC  ac_chan  = { 1, "Popup",      { "channels", NULL }};
933 struct DO_AC  ac_conf  = { 1, "Popup",      { "config",   NULL }};
934 struct DO_AC  ac_launch = { 1, "Popup",      { "launcher",  NULL }};
935 struct DO_AC  ac_zap   = { 0, "Zap",        { NULL }};
936 
937 static void
938 menu_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
939 {
940     struct ng_attribute *attr;
941     long  cd = (long)clientdata;
942     int   j;
943 
944     switch (cd) {
945 #if 0
946     case 10:
947         attr = ng_attr_byid(a_drv,ATTR_ID_NORM);
948         if (-1 != (j=popup_menu(widget,"TV Norm",attr->choices)))
949             do_va_cmd(2,"setnorm",ng_attr_getstr(attr,j));
950         break;
951     case 11:
952         attr = ng_attr_byid(a_drv,ATTR_ID_INPUT);
953         if (-1 != (j=popup_menu(widget,"Video Source",attr->choices)))
954             do_va_cmd(2,"setinput",ng_attr_getstr(attr,j));
955         break;
956 #endif
957     case 12:
958         if (-1 != (j=popup_menu(widget,"Freq table",chanlist_names)))
959             do_va_cmd(2,"setfreqtab",chanlist_names[j].str);
960         break;
961     case 13:
962         attr = ng_attr_byid(attrs,ATTR_ID_AUDIO_MODE);
963         if (NULL != attr) {
964             int i,mode = attr->read(attr);
965             for (i = 1; attr->choices[i].str != NULL; i++) {
966                 attr->choices[i].nr =
967                     (1 << (i-1)) & mode ? (1 << (i-1)) : -1;
968             }
969             if (-1 != (j=popup_menu(widget,"Audio",attr->choices)))
970                 change_audio(attr->choices[j].nr);
971         }
972         break;
973     case 14:
974         if (-1 != (j=popup_menu(widget,"Capture",cap_list)))
975             do_va_cmd(2,"capture",cap_list[j].str);
976         break;
977 
978     case 20:
979         if (-1 != (j=popup_menu(widget,MOVIE_DRIVER,m_movie_driver))) {
980             int i = 0;
981             struct list_head *item;
982             struct ng_writer *writer = NULL;
983             
984             list_for_each(item,&ng_writers) {
985                 if (i++ == j)
986                     writer = list_entry(item,struct ng_writer, list);
987             }
988             do_va_cmd(3,"movie","driver",writer->name);
989         }
990         break;
991     case 21:
992         if (-1 != (j=popup_menu(widget,MOVIE_AUDIO,m_movie_audio)))
993             do_va_cmd(3,"movie","audio",
994                       movie_driver->audio[j].name ?
995                       movie_driver->audio[j].name :
996                       "none");
997         break;
998     case 22:
999         if (-1 != (j=popup_menu(widget,MOVIE_RATE,m_movie_rate)))
1000             do_va_cmd(3,"movie","rate",m_movie_rate[j].str);
1001         break;
1002     case 23:
1003         if (-1 != (j=popup_menu(widget,MOVIE_VIDEO,m_movie_video)))
1004             do_va_cmd(3,"movie","video",movie_driver->video[j].name);
1005         break;
1006     case 24:
1007         if (-1 != (j=popup_menu(widget,MOVIE_FPS,m_movie_fps)))
1008             do_va_cmd(3,"movie","fps",m_movie_fps[j].str);
1009         break;
1010     default:
1011         /* nothing */
1012         break;
1013     }
1014 }
1015 
1016 static void
1017 jump_scb(Widget widget, XtPointer clientdata, XtPointer call_data)
1018 {
1019     struct xaw_attribute *a = clientdata;
1020     struct ng_attribute *attr = a->attr;
1021     const char *name;
1022     char val[16];
1023     int  value,range;
1024 
1025     range = attr->max - attr->min;
1026     value = (int)(*(float*)call_data * range) + attr->min;
1027     if (debug)
1028         fprintf(stderr,"scroll: value is %d\n",value);
1029     if (value < attr->min)
1030         value = attr->min;
1031     if (value > attr->max)
1032         value = attr->max;
1033     sprintf(val,"%d",value);
1034 
1035     if (a) {
1036         name = a->attr->name;
1037         do_va_cmd(3,"setattr",name,val);
1038     } else {
1039         name = XtName(XtParent(widget));
1040         do_va_cmd(2,name,val);
1041     }
1042 }
1043 
1044 static void
1045 scroll_scb(Widget widget, XtPointer clientdata, XtPointer call_data)
1046 {
1047     long      move = (long)call_data;
1048     Dimension length;
1049     float     shown,top1,top2;
1050 
1051     XtVaGetValues(widget,
1052                   XtNlength,     &length,
1053                   XtNshown,      &shown,
1054                   XtNtopOfThumb, &top1,
1055                   NULL);
1056 
1057     top2 = top1 + (float)move/length/5;
1058     if (top2 < 0) top2 = 0;
1059     if (top2 > 1) top2 = 1;
1060 #if 1
1061     fprintf(stderr,"scroll by %ld\tlength %d\tshown %f\ttop %f => %f\n",
1062             move,length,shown,top1,top2);
1063 #endif
1064     jump_scb(widget,clientdata,&top2);
1065 }
1066 
1067 static void
1068 attr_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
1069 {
1070     struct xaw_attribute *a = clientdata;
1071     int j;
1072 
1073     switch (a->attr->type) {
1074     case ATTR_TYPE_CHOICE:
1075         j=popup_menu(widget,a->attr->name,a->attr->choices);
1076         if (-1 != j)
1077             do_va_cmd(3,"setattr",a->attr->name,a->attr->choices[j].str);
1078         break;
1079     case ATTR_TYPE_BOOL:
1080         do_va_cmd(3,"setattr",a->attr->name,"toggle");
1081         break;
1082     }
1083 }
1084 
1085 static void
1086 add_attr_option(Widget paned, struct ng_attribute *attr)
1087 {
1088     struct xaw_attribute *a;
1089     Widget p,l;
1090 
1091     a = malloc(sizeof(*a));
1092     memset(a,0,sizeof(*a));
1093     a->attr = attr;
1094     
1095     switch (attr->type) {
1096     case ATTR_TYPE_BOOL:
1097     case ATTR_TYPE_CHOICE:
1098         a->cmd = XtVaCreateManagedWidget(attr->name,
1099                                          commandWidgetClass, paned,
1100                                          PANED_FIX,
1101                                          NULL);
1102         XtAddCallback(a->cmd,XtNcallback,attr_cb,a);
1103         break;
1104     case ATTR_TYPE_INTEGER:
1105         p = XtVaCreateManagedWidget(attr->name,
1106                                     panedWidgetClass, paned,
1107                                     XtNorientation, XtEvertical,
1108                                     PANED_FIX,
1109                                     NULL);
1110         l = XtVaCreateManagedWidget("l",labelWidgetClass, p,
1111                                     XtNshowGrip, False,
1112                                     NULL);
1113         a->scroll = XtVaCreateManagedWidget("s",scrollbarWidgetClass,p,
1114                                             PANED_FIX,
1115                                             NULL);
1116         XtAddCallback(a->scroll, XtNjumpProc,   jump_scb,   a);
1117         XtAddCallback(a->scroll, XtNscrollProc, scroll_scb, a);
1118         if (attr->id >= ATTR_ID_COUNT)
1119             XtVaSetValues(l,XtNlabel,attr->name,NULL);
1120         break;
1121     }
1122     a->next = xaw_attrs;
1123     xaw_attrs = a;
1124 }
1125 
1126 static void
1127 create_optwin(void)
1128 {
1129     Widget c;
1130 
1131     opt_shell = XtVaAppCreateShell("Options", "Xawtv",
1132                                    topLevelShellWidgetClass,
1133                                    dpy,
1134                                    XtNclientLeader,app_shell,
1135                                    XtNvisual,vinfo.visual,
1136                                    XtNcolormap,colormap,
1137                                    XtNdepth,vinfo.depth,
1138                                    NULL);
1139     XtOverrideTranslations(opt_shell, XtParseTranslationTable
1140                            ("<Message>WM_PROTOCOLS: Popup()"));
1141     opt_paned = XtVaCreateManagedWidget("paned", panedWidgetClass, opt_shell,
1142                                         NULL);
1143     
1144     c = XtVaCreateManagedWidget("mute", commandWidgetClass, opt_paned,
1145                                 PANED_FIX, NULL);
1146     XtAddCallback(c,XtNcallback,command_cb,(XtPointer)&cmd_mute);
1147     
1148     c = XtVaCreateManagedWidget("fs", commandWidgetClass, opt_paned,
1149                                 PANED_FIX, NULL);
1150     XtAddCallback(c,XtNcallback,command_cb,(XtPointer)&cmd_fs);
1151 
1152     c = XtVaCreateManagedWidget("grabppm", commandWidgetClass, opt_paned,
1153                                 PANED_FIX, NULL);
1154     XtAddCallback(c,XtNcallback,command_cb,(XtPointer)&cmd_ppm);
1155     c = XtVaCreateManagedWidget("grabjpeg", commandWidgetClass, opt_paned,
1156                                 PANED_FIX, NULL);
1157     XtAddCallback(c,XtNcallback,command_cb,(XtPointer)&cmd_jpeg);
1158     c = XtVaCreateManagedWidget("recavi", commandWidgetClass, opt_paned,
1159                                 PANED_FIX, NULL);
1160     XtAddCallback(c,XtNcallback,action_cb,(XtPointer)&ac_avi);
1161     c = XtVaCreateManagedWidget("chanwin", commandWidgetClass, opt_paned,
1162                                 PANED_FIX, NULL);
1163     XtAddCallback(c,XtNcallback,action_cb,(XtPointer)&ac_chan);
1164     c = XtVaCreateManagedWidget("confwin", commandWidgetClass, opt_paned,
1165                                 PANED_FIX, NULL);
1166     XtAddCallback(c,XtNcallback,action_cb,(XtPointer)&ac_conf);
1167     c = XtVaCreateManagedWidget("launchwin", commandWidgetClass, opt_paned,
1168                                 PANED_FIX, NULL);
1169     XtAddCallback(c,XtNcallback,action_cb,(XtPointer)&ac_launch);
1170     c = XtVaCreateManagedWidget("zap", commandWidgetClass, opt_paned,
1171                                 PANED_FIX, NULL);
1172     XtAddCallback(c,XtNcallback,action_cb,(XtPointer)&ac_zap);
1173     if (wm_stay_on_top) {
1174         c = XtVaCreateManagedWidget("top", commandWidgetClass, opt_paned,
1175                                     PANED_FIX, NULL);
1176         XtAddCallback(c,XtNcallback,action_cb,(XtPointer)&ac_top);
1177     }
1178 }
1179 
1180 static void
1181 create_attr_widgets(void)
1182 {
1183     struct ng_attribute *attr;
1184     Widget c;
1185 
1186     /* menus / multiple choice options */
1187     attr = ng_attr_byid(attrs,ATTR_ID_NORM);
1188     if (NULL != attr)
1189         add_attr_option(opt_paned,attr);
1190     attr = ng_attr_byid(attrs,ATTR_ID_INPUT);
1191     if (NULL != attr)
1192         add_attr_option(opt_paned,attr);
1193     attr = ng_attr_byid(attrs,ATTR_ID_AUDIO_MODE);
1194     if (NULL != attr)
1195         add_attr_option(opt_paned,attr);
1196 
1197     if (f_drv & CAN_TUNE) {
1198         c_freq = XtVaCreateManagedWidget("freq", commandWidgetClass, opt_paned,
1199                                          PANED_FIX, NULL);
1200         XtAddCallback(c_freq,XtNcallback,menu_cb,(XtPointer)12);
1201     }
1202     c_cap = XtVaCreateManagedWidget("cap", commandWidgetClass, opt_paned,
1203                                     PANED_FIX, NULL);
1204     XtAddCallback(c_cap,XtNcallback,menu_cb,(XtPointer)14);
1205 
1206     for (attr = attrs; attr->name != NULL; attr++) {
1207         if (attr->id < ATTR_ID_COUNT)
1208             continue;
1209         if (attr->type != ATTR_TYPE_CHOICE)
1210             continue;
1211         add_attr_option(opt_paned,attr);
1212     }
1213     
1214     /* integer options */
1215     attr = ng_attr_byid(attrs,ATTR_ID_BRIGHT);
1216     if (NULL != attr)
1217         add_attr_option(opt_paned,attr);
1218     attr = ng_attr_byid(attrs,ATTR_ID_HUE);
1219     if (NULL != attr)
1220         add_attr_option(opt_paned,attr);
1221     attr = ng_attr_byid(attrs,ATTR_ID_CONTRAST);
1222     if (NULL != attr)
1223         add_attr_option(opt_paned,attr);
1224     attr = ng_attr_byid(attrs,ATTR_ID_COLOR);
1225     if (NULL != attr)
1226         add_attr_option(opt_paned,attr);
1227     attr = ng_attr_byid(attrs,ATTR_ID_VOLUME);
1228     if (NULL != attr)
1229         add_attr_option(opt_paned,attr);
1230 
1231     for (attr = attrs; attr->name != NULL; attr++) {
1232         if (attr->id < ATTR_ID_COUNT)
1233             continue;
1234         if (attr->type != ATTR_TYPE_INTEGER)
1235             continue;
1236         add_attr_option(opt_paned,attr);
1237     }
1238 
1239     /* boolean options */
1240     for (attr = attrs; attr->name != NULL; attr++) {
1241         if (attr->id < ATTR_ID_COUNT)
1242             continue;
1243         if (attr->type != ATTR_TYPE_BOOL)
1244             continue;
1245         add_attr_option(opt_paned,attr);
1246     }
1247 
1248     /* quit */
1249     c = XtVaCreateManagedWidget("quit", commandWidgetClass, opt_paned,
1250                                 PANED_FIX, NULL);
1251     XtAddCallback(c,XtNcallback,ExitCB,NULL);
1252 }
1253 
1254 /*--- avi recording ------------------------------------------------------*/
1255 
1256 static void
1257 exec_record(Widget widget, XtPointer client_data, XtPointer calldata)
1258 {
1259     if (!(f_drv & CAN_CAPTURE)) {
1260         fprintf(stderr,"grabbing: not supported [try -noxv switch?]\n");
1261         return;
1262     }
1263 
1264     if (rec_work_id) {
1265         do_va_cmd(2,"movie","stop");
1266     } else {
1267         do_va_cmd(2,"movie","start");
1268     }
1269     return;
1270 }
1271 
1272 static void
1273 exec_player_cb(Widget widget, XtPointer client_data, XtPointer calldata)
1274 {
1275     char *filename;
1276 
1277     XtVaGetValues(w_movie_fvideo,XtNstring,&filename,NULL);
1278     filename = tilde_expand(filename);
1279     exec_player(filename);
1280 }
1281 
1282 static void
1283 do_movie_record(int argc, char **argv)
1284 {
1285     char *fvideo,*faudio;
1286     struct ng_video_fmt video;
1287     struct ng_audio_fmt audio;
1288     const struct ng_writer *wr;
1289     int i;
1290 
1291     /* set parameters */
1292     if (argc > 1 && 0 == strcasecmp(argv[0],"driver")) {
1293         struct list_head *item;
1294         struct ng_writer *writer;
1295         i = 0;
1296         list_for_each(item,&ng_writers) {
1297             writer = list_entry(item, struct ng_writer, list);
1298             if (0 == strcasecmp(argv[1],writer->name)) {
1299                 movie_driver = writer;
1300                 i_movie_driver = i;
1301             }
1302             i++;
1303         }
1304 
1305         set_menu_val(w_movie_driver,MOVIE_DRIVER,
1306                      m_movie_driver,i_movie_driver);
1307         update_movie_menus();
1308         set_menu_val(w_movie_audio,MOVIE_AUDIO,
1309                      m_movie_audio,movie_audio);
1310         set_menu_val(w_movie_video,MOVIE_VIDEO,
1311                      m_movie_video,movie_video);
1312         return;
1313     }
1314     if (argc > 1 && 0 == strcasecmp(argv[0],"fvideo")) {
1315         XtVaSetValues(w_movie_fvideo,XtNstring,argv[1],NULL);
1316         return;
1317     }
1318     if (argc > 1 && 0 == strcasecmp(argv[0],"faudio")) {
1319         XtVaSetValues(w_movie_faudio,XtNstring,argv[1],NULL);
1320         return;
1321     }
1322     if (argc > 1 && 0 == strcasecmp(argv[0],"audio")) {
1323         for (i = 0; NULL != movie_driver->audio[i].name; i++) {
1324             if (0 == strcasecmp(argv[1],movie_driver->audio[i].name))
1325                 movie_audio = m_movie_audio[i].nr;
1326         }
1327         if (0 == strcmp(argv[1],"none"))
1328             movie_audio = m_movie_audio[i].nr;
1329         set_menu_val(w_movie_audio,MOVIE_AUDIO,
1330                      m_movie_audio,movie_audio);
1331         return;
1332     }
1333     if (argc > 1 && 0 == strcasecmp(argv[0],"rate")) {
1334         for (i = 0; m_movie_rate[i].str != NULL; i++)
1335             if (atoi(argv[1]) == m_movie_rate[i].nr)
1336                 movie_rate = m_movie_rate[i].nr;
1337         set_menu_val(w_movie_rate,MOVIE_RATE,
1338                      m_movie_rate,movie_rate);
1339     }
1340     if (argc > 1 && 0 == strcasecmp(argv[0],"video")) {
1341         for (i = 0; NULL != movie_driver->video[i].name; i++)
1342             if (0 == strcasecmp(argv[1],movie_driver->video[i].name))
1343                 movie_video = m_movie_video[i].nr;
1344         set_menu_val(w_movie_video,MOVIE_VIDEO,
1345                      m_movie_video,movie_video);
1346         return;
1347     }
1348     if (argc > 1 && 0 == strcasecmp(argv[0],"fps")) {
1349         for (i = 0; m_movie_fps[i].str != NULL; i++) {
1350             int fps = (int)(atof(argv[1]) * 1000 + .5);
1351             if (fps == m_movie_fps[i].nr)
1352                 movie_fps = m_movie_fps[i].nr;
1353         }
1354         set_menu_val(w_movie_fps,MOVIE_FPS,
1355                      m_movie_fps,movie_fps);
1356     }
1357 
1358     /* start */
1359     if (argc > 0 && 0 == strcasecmp(argv[0],"start")) {
1360         if (0 != cur_movie)
1361             return; /* records already */
1362         cur_movie = 1;
1363         movie_blit = (cur_capture == CAPTURE_GRABDISPLAY);
1364         video_gd_suspend();
1365 
1366         XtVaGetValues(w_movie_fvideo,XtNstring,&fvideo,NULL);
1367         XtVaGetValues(w_movie_faudio,XtNstring,&faudio,NULL);
1368         fvideo = tilde_expand(fvideo);
1369         faudio = tilde_expand(faudio);
1370 
1371         memset(&video,0,sizeof(video));
1372         memset(&audio,0,sizeof(audio));
1373 
1374         wr = movie_driver;
1375         video.fmtid  = wr->video[movie_video].fmtid;
1376         video.width  = cur_tv_width;
1377         video.height = cur_tv_height;
1378         if (NULL != wr->audio[movie_audio].name) {
1379             audio.fmtid  = wr->audio[movie_audio].fmtid;
1380             audio.rate   = movie_rate;
1381         } else {
1382             audio.fmtid  = AUDIO_NONE;
1383         }
1384 
1385         movie_state = movie_writer_init
1386             (fvideo, faudio, wr,
1387              &video, wr->video[movie_video].priv, movie_fps,
1388              &audio, wr->audio[movie_audio].priv, args.dspdev,
1389              args.bufcount,args.parallel);
1390         if (NULL == movie_state) {
1391             /* init failed */
1392             video_gd_restart();
1393             cur_movie = 0;
1394             /* hmm, not the most elegant way to flag an error ... */
1395             XtVaSetValues(w_movie_status,XtNlabel,"error [init]",NULL);
1396             return;
1397         }
1398         if (0 != movie_writer_start(movie_state)) {
1399             /* start failed */
1400             movie_writer_stop(movie_state);
1401             video_gd_restart();
1402             cur_movie = 0;
1403             /* hmm, not the most elegant way to flag an error ... */
1404             XtVaSetValues(w_movie_status,XtNlabel,"error [start]",NULL);
1405             return;
1406         }
1407         rec_work_id  = XtAppAddWorkProc(app_context,rec_work,NULL);
1408         XtVaSetValues(w_movie_status,XtNlabel,"recording",NULL);
1409         return;
1410     }
1411     
1412     /* stop */
1413     if (argc > 0 && 0 == strcasecmp(argv[0],"stop")) {
1414         if (0 == cur_movie)
1415             return; /* nothing to stop here */
1416 
1417         movie_writer_stop(movie_state);
1418         XtRemoveWorkProc(rec_work_id);
1419         rec_work_id = 0;
1420         video_gd_restart();
1421         cur_movie = 0;
1422         return;
1423     }
1424 }
1425 
1426 static void
1427 do_rec_status(char *message)
1428 {
1429     XtVaSetValues(w_movie_status,XtNlabel,message,NULL);
1430 }
1431 
1432 #define FIX_LEFT_TOP        \
1433     XtNleft,XawChainLeft,   \
1434     XtNright,XawChainRight, \
1435     XtNtop,XawChainTop,     \
1436     XtNbottom,XawChainTop
1437 
1438 static void
1439 create_strwin(void)
1440 {
1441     Widget form,label,button,text;
1442 
1443     str_shell = XtVaAppCreateShell("Streamer", "Xawtv",
1444                                    topLevelShellWidgetClass,
1445                                    dpy,
1446                                    XtNclientLeader,app_shell,
1447                                    XtNvisual,vinfo.visual,
1448                                    XtNcolormap,colormap,
1449                                    XtNdepth,vinfo.depth,
1450                                    NULL);
1451     XtOverrideTranslations(str_shell, XtParseTranslationTable
1452                            ("<Message>WM_PROTOCOLS: Popup()"));
1453 
1454     form = XtVaCreateManagedWidget("form", formWidgetClass, str_shell,
1455                                    NULL);
1456 
1457     /* driver */
1458     button = XtVaCreateManagedWidget("driver", commandWidgetClass, form,
1459                                      FIX_LEFT_TOP,
1460                                      NULL);
1461     w_movie_driver = button;
1462 
1463     /* movie filename */
1464     label = XtVaCreateManagedWidget("vlabel", labelWidgetClass, form,
1465                                     FIX_LEFT_TOP,
1466                                     XtNfromVert, button,
1467                                     NULL);
1468     text = XtVaCreateManagedWidget("vname", asciiTextWidgetClass, form,
1469                                    FIX_LEFT_TOP,
1470                                    XtNfromVert, label,
1471                                    NULL);
1472     w_movie_fvideo = text;
1473     
1474     /* audio filename */
1475     label = XtVaCreateManagedWidget("alabel", labelWidgetClass, form,
1476                                     FIX_LEFT_TOP,
1477                                     XtNfromVert, text,
1478                                     NULL);
1479     w_movie_flabel = label;
1480     text= XtVaCreateManagedWidget("aname", asciiTextWidgetClass, form,
1481                                   FIX_LEFT_TOP,
1482                                   XtNfromVert, label,
1483                                   NULL);
1484     w_movie_faudio = text;
1485 
1486     /* audio format */
1487     button = XtVaCreateManagedWidget("audio", commandWidgetClass, form,
1488                                      FIX_LEFT_TOP,
1489                                      XtNfromVert, text,
1490                                      NULL);
1491     w_movie_audio = button;
1492     button = XtVaCreateManagedWidget("rate", commandWidgetClass, form,
1493                                      FIX_LEFT_TOP,
1494                                      XtNfromVert, button,
1495                                      NULL);
1496     w_movie_rate = button;
1497 
1498     /* video format */
1499     button = XtVaCreateManagedWidget("video", commandWidgetClass, form,
1500                                      FIX_LEFT_TOP,
1501                                      XtNfromVert, button,
1502                                      NULL);
1503     w_movie_video = button;
1504     button = XtVaCreateManagedWidget("fps", commandWidgetClass, form,
1505                                      FIX_LEFT_TOP,
1506                                      XtNfromVert, button,
1507                                      NULL);
1508     w_movie_fps = button;
1509     label = XtVaCreateManagedWidget("size", labelWidgetClass, form,
1510                                     FIX_LEFT_TOP,
1511                                     XtNfromVert, button,
1512                                     NULL);
1513     w_movie_size = label;
1514 
1515     /* status line */
1516     label = XtVaCreateManagedWidget("status", labelWidgetClass, form,
1517                                     FIX_LEFT_TOP,
1518                                     XtNfromVert, label,
1519                                     XtNlabel,    "",
1520                                     NULL);
1521     w_movie_status = label;
1522 
1523     /* cmd buttons */
1524     button = XtVaCreateManagedWidget("streamer", commandWidgetClass, form,
1525                                      FIX_LEFT_TOP,
1526                                      XtNfromVert, label,
1527                                      NULL);
1528     XtAddCallback(button,XtNcallback,exec_record,NULL);
1529     
1530     button = XtVaCreateManagedWidget("xanim", commandWidgetClass, form,
1531                                      FIX_LEFT_TOP,
1532                                      XtNfromVert, button,
1533                                      NULL);
1534     XtAddCallback(button,XtNcallback,exec_player_cb,NULL);
1535 
1536 #if 0
1537     label = XtVaCreateManagedWidget("olabel", labelWidgetClass, form,
1538                                     FIX_LEFT_TOP,
1539                                     XtNfromVert,button,
1540                                     NULL);
1541     str_text = XtVaCreateManagedWidget("output", asciiTextWidgetClass, form,
1542                                        XtNleft,XawChainLeft,
1543                                        XtNright,XawChainRight,
1544                                        XtNtop,XawChainTop,
1545                                        XtNbottom,XawChainBottom,
1546                                        XtNfromVert,label,
1547                                        NULL);
1548 #endif
1549 
1550     XtAddCallback(w_movie_driver,XtNcallback,menu_cb,(XtPointer)20);
1551     XtAddCallback(w_movie_audio,XtNcallback,menu_cb,(XtPointer)21);
1552     XtAddCallback(w_movie_rate,XtNcallback,menu_cb,(XtPointer)22);
1553     XtAddCallback(w_movie_video,XtNcallback,menu_cb,(XtPointer)23);
1554     XtAddCallback(w_movie_fps,XtNcallback,menu_cb,(XtPointer)24);
1555 }
1556 
1557 /*--- launcher window -----------------------------------------------------*/
1558 
1559 static void
1560 create_launchwin(void)
1561 {
1562     launch_shell = XtVaAppCreateShell("Launcher", "Xawtv",
1563                                      topLevelShellWidgetClass,
1564                                      dpy,
1565                                      XtNclientLeader,app_shell,
1566                                      XtNvisual,vinfo.visual,
1567                                      XtNcolormap,colormap,
1568                                      XtNdepth,vinfo.depth,
1569                                      NULL);
1570     XtOverrideTranslations(launch_shell, XtParseTranslationTable
1571                            ("<Message>WM_PROTOCOLS: Popup()"));
1572     launch_paned = XtVaCreateManagedWidget("paned", panedWidgetClass,
1573                                           launch_shell, NULL);
1574 }
1575 
1576 /*--- main ---------------------------------------------------------------*/
1577 
1578 int
1579 main(int argc, char *argv[])
1580 {
1581     int            i;
1582     unsigned long  freq;
1583 
1584     hello_world("xawtv");
1585     progname = strdup(argv[0]);
1586 
1587     /* toplevel */
1588     XtSetLanguageProc(NULL,NULL,NULL);
1589     app_shell = XtVaAppInitialize(&app_context, "Xawtv",
1590                                   opt_desc, opt_count,
1591                                   &argc, argv,
1592                                   fallback_ressources,
1593                                   NULL);
1594     dpy = XtDisplay(app_shell);
1595     init_atoms(dpy);
1596 
1597     /* command line args */
1598     ng_init();
1599     handle_cmdline_args();
1600 
1601     /* device scan */
1602     if (args.hwscan) {
1603         fprintf(stderr,"looking for available devices\n");
1604 #ifdef HAVE_LIBXV
1605         xv_video_init(-1,1);
1606 #endif
1607         grabber_scan();
1608     }
1609     
1610     /* look for a useful visual */
1611     visual_init("xawtv","Xawtv");
1612 
1613     /* remote display? */
1614     do_overlay = !args.remote;
1615     if (do_overlay)
1616         x11_check_remote();
1617     v4lconf_init();
1618 
1619     /* x11 stuff */
1620     XtAppAddActions(app_context,actionTable,
1621                     sizeof(actionTable)/sizeof(XtActionsRec));
1622     x11_misc_init(dpy);
1623     if (debug)
1624         fprintf(stderr,"main: dga extention...\n");
1625     xfree_dga_init(dpy);
1626     if (debug)
1627         fprintf(stderr,"main: xinerama extention...\n");
1628     xfree_xinerama_init(dpy);
1629 #ifdef HAVE_LIBXV
1630     if (debug)
1631         fprintf(stderr,"main: xvideo extention [video]...\n");
1632     if (args.xv_video)
1633         xv_video_init(args.xv_port,0);
1634     if (debug)
1635         fprintf(stderr,"main: xvideo extention [image]...\n");
1636     if (args.xv_image)
1637         xv_image_init(dpy);
1638 #endif
1639     
1640     /* set hooks (command.c) */
1641     update_title        = new_title;
1642     display_message     = new_message;
1643 #if TT
1644     vtx_message         = display_vtx;
1645 #endif
1646 #ifdef HAVE_ZVBI
1647     vtx_subtitle        = display_subtitle;
1648 #endif
1649     attr_notify         = new_attr;
1650     volume_notify       = new_volume;
1651     freqtab_notify      = new_freqtab;
1652     setfreqtab_notify   = new_freqtab;
1653     setstation_notify   = new_channel;
1654     set_capture_hook    = do_capture;
1655     fullscreen_hook     = do_fullscreen;
1656     movie_hook          = do_movie_record;
1657     rec_status          = do_rec_status;
1658     exit_hook           = do_exit;
1659     capture_get_hook    = video_gd_suspend;
1660     capture_rel_hook    = video_gd_restart;
1661     channel_switch_hook = pixit;
1662     
1663     if (debug)
1664         fprintf(stderr,"main: init main window...\n");
1665     tv = video_init(app_shell, &vinfo, simpleWidgetClass,
1666                     args.bpp, args.gl);
1667     XtAddEventHandler(XtParent(tv),StructureNotifyMask, True,
1668                       resize_event, NULL);
1669     if (debug)
1670         fprintf(stderr,"main: install signal handlers...\n");
1671     xt_siginit();
1672     if (NULL == drv) {
1673         if (debug)
1674             fprintf(stderr,"main: open grabber device...\n");
1675         grabber_init();
1676     }
1677 
1678     /* create windows */
1679     XSetIOErrorHandler(x11_ctrl_alt_backspace);
1680     if (debug)
1681         fprintf(stderr,"main: checking wm...\n");
1682     wm_detect(dpy);
1683     if (debug)
1684         fprintf(stderr,"main: creating windows ...\n");
1685     create_optwin();
1686     create_onscreen(labelWidgetClass);
1687     create_vtx();
1688     create_chanwin();
1689     create_confwin();
1690     create_strwin();
1691     create_launchwin();
1692 
1693     /* read config file + related settings */
1694     if (debug)
1695         fprintf(stderr,"main: init frequency tables ...\n");
1696     freq_init();
1697     if (args.readconfig) {
1698         if (debug)
1699             fprintf(stderr,"main: read config file ...\n");
1700         read_config(args.conffile ? args.conffile : NULL, &argc, argv);
1701     }
1702     if (0 != strlen(mixerdev)) {
1703         struct ng_attribute *attr;
1704         if (debug)
1705             fprintf(stderr,"main: open mixer device...\n");
1706         if (NULL != (attr = ng_mix_init(mixerdev,mixerctl)))
1707             add_attrs(attr);
1708     }
1709     init_movie_menus();
1710     create_attr_widgets();
1711     
1712     xt_vm_randr_input_init(dpy);
1713     
1714     if (debug)
1715         fprintf(stderr,"main: mapping main window ...\n");
1716     XtRealizeWidget(app_shell);
1717     create_pointers(app_shell);
1718     create_bitmaps(app_shell);
1719     XDefineCursor(dpy, XtWindow(app_shell), left_ptr);
1720     XSetWMProtocols(XtDisplay(app_shell), XtWindow(app_shell),
1721                     &WM_DELETE_WINDOW, 1);
1722 
1723     XtVaSetValues(app_shell,
1724                   XtNwidthInc,  WIDTH_INC,
1725                   XtNheightInc, HEIGHT_INC,
1726                   XtNminWidth,  WIDTH_INC,
1727                   XtNminHeight, HEIGHT_INC,
1728                   NULL);
1729     XtVaSetValues(chan_shell,
1730                   XtNwidth,pix_width*pix_cols+30,
1731                   NULL);
1732 
1733     /* mouse pointer magic */
1734     XtAddEventHandler(tv, PointerMotionMask, True, mouse_event, NULL);
1735     mouse_event(tv,NULL,NULL,NULL);
1736 
1737     /* init hardware */
1738     if (debug)
1739         fprintf(stderr,"main: initialize hardware ...\n");
1740     attr_init();
1741     audio_on();
1742     audio_init();
1743 
1744     /* build channel list */
1745     if (args.readconfig) {
1746         if (debug)
1747             fprintf(stderr,"main: parse channels from config file ...\n");
1748         parse_config();
1749     }
1750     channel_menu();
1751 
1752     xt_handle_pending(dpy);
1753     init_overlay();
1754 
1755     set_property(0,NULL,NULL);
1756     if (optind+1 == argc) {
1757         do_va_cmd(2,"setstation",argv[optind]);
1758     } else {
1759         if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) {
1760             for (i = 0; i < chancount; i++)
1761                 if (chanlist[i].freq == freq*1000/16) {
1762                     do_va_cmd(2,"setchannel",chanlist[i].name);
1763                     break;
1764                 }
1765         }
1766         if (-1 == cur_channel) {
1767             if (count > 0) {
1768                 if (debug)
1769                     fprintf(stderr,"main: tuning first station\n");
1770                 do_va_cmd(2,"setstation","");
1771             } else {
1772                 if (debug)
1773                     fprintf(stderr,"main: setting defaults\n");
1774                 set_defaults();
1775             }
1776         } else {
1777             if (debug)
1778                 fprintf(stderr,"main: known station tuned, not changing\n");
1779         }
1780     }
1781     XtAddEventHandler(tv,ExposureMask, True, tv_expose_event, NULL);
1782 
1783     if (args.fullscreen) {
1784         XSync(dpy,False);
1785         do_fullscreen();
1786     } else {
1787         XtAppAddWorkProc(app_context,MyResize,NULL);
1788     }
1789 
1790     sprintf(modename,"%dx%d, ",
1791             XtScreen(app_shell)->width,XtScreen(app_shell)->height);
1792     strcat(modename,ng_vfmt_to_desc[x11_dpy_fmtid]);
1793     new_message(modename);
1794     if (!have_config)
1795         XtCallActionProc(tv,"Help",NULL,NULL,0);
1796 
1797     xt_main_loop();
1798     return 0;
1799 }
1800 
  This page was automatically generated by the LXR engine.