1 /*
2  * tvscreen.c
3  *
4  * API for determining basic capabilities of the video card on an
5  *   X server screen.
6  *
7  * (C) 1997 Randall Hopper
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are
11  * met: 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer. 2.
13  * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 /*      ******************** Include Files                ************** */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/ipc.h>
39 #include <sys/shm.h>
40 #include <X11/Xlib.h>                       /*  xf86dga.h needs this       */
41 #ifdef HAVE_XFREE86
42 #  include <X11/Xproto.h>                   /*  XF86 pre-4.0 needs for dga */
43 #  include <X11/extensions/xf86dga.h>
44 #  include <X11/Xmd.h>                      /*  xf86dgastr.h needs this    */
45 #  include <X11/extensions/xf86dgastr.h>
46 #  include <X11/extensions/xf86vmstr.h>
47 #endif
48 #include <X11/extensions/XShm.h>
49 #include <X11/StringDefs.h>
50 #include <X11/Intrinsic.h>
51 #include <X11/Shell.h>
52 #include <X11/cursorfont.h>
53 #include "tvdefines.h"
54 #include "tvtypes.h"
55 #include "tvscreen.h"
56 #include "tvmenu.h"
57 #include "annot.h"
58 #include "glob.h"
59 #include "eventnames.h"
60 #include "appear_dlg.h"
61 #include "videolib.h"
62 
63 /*      ******************** Local defines                ************** */
64 
65 #define VMODE_EXT_MIN_MAJOR 0
66 #define VMODE_EXT_MIN_MINOR 5
67 
68 #define VERS_SAME_OR_NEWER( major, minor, major_min, minor_min ) \
69            (( (major)  > (major_min) ) || \
70             (( (major) == (major_min) ) && ( (minor) >= (minor_min) )) )
71 
72 #define RES_MULT_OK(d,c) \
73         (( (d)->geom.w == (d)->geom.w / (c)->width_res * (c)->width_res   ) &&\
74          ( (d)->geom.h == (d)->geom.h / (c)->height_res * (c)->height_res ))
75 
76 #define DIRECTVID_RESTART_DELAY_MS   200
77 #define CURSOR_TURNOFF_DELAY_MS     1000
78 
79 #define REFRESH_SLACK_PIXELS 30
80 
81 static XtIntervalId S_restart_timer;
82 static TV_BOOL      S_restart_timer_set = False;
83 
84 #define CURSOR_SIZE  16
85 
86 /*      ******************** Forward declarations         ************** */
87 /*      ******************** Private variables            ************** */
88 /*      ******************** Function Definitions         ************** */
89 
90 /**@BEGINFUNC**************************************************************
91 
92     Prototype  : static INT32 TVSCREENGetCurVidMode(
93                       TV_XSCREEN *s )
94 
95     Purpose    : Returns the index of the current video mode in the
96                  s->vm_list video mode list.
97 
98     Programmer : 13-Apr-97  Randall Hopper
99 
100     Parameters : s - I: screen def struct
101 
102     Returns    : On success, index into s->vm_list
103                  On failure, -1
104                    (XF86 video mode extension not supported, or not
105                    found in list)
106 
107     Globals    : None.
108 
109  **@ENDFUNC*****************************************************************/
110 
TVSCREENGetCurVidMode(TV_XSCREEN * s)111 static TV_INT32 TVSCREENGetCurVidMode(
112                     TV_XSCREEN *s )
113 {
114     if ( !s->vmode_ext_supported )
115         return -1;
116 
117 #ifdef HAVE_XFREE86
118     {
119         int                  vm,
120                              dot_clock;
121         XF86VidModeModeLine  vm_info;
122 
123         XF86VidModeGetModeLine( s->display, s->screen, &dot_clock,
124                                 &vm_info );
125 
126         for ( vm = 0; vm < s->vm_list_len; vm++ )
127             if (( vm_info.hdisplay   == (s->vm_list)[vm]->hdisplay   ) &&
128                 ( vm_info.hsyncstart == (s->vm_list)[vm]->hsyncstart ) &&
129                 ( vm_info.hsyncend   == (s->vm_list)[vm]->hsyncend   ) &&
130                 ( vm_info.htotal     == (s->vm_list)[vm]->htotal     ) &&
131                 ( vm_info.vdisplay   == (s->vm_list)[vm]->vdisplay   ) &&
132                 ( vm_info.vsyncstart == (s->vm_list)[vm]->vsyncstart ) &&
133                 ( vm_info.vsyncend   == (s->vm_list)[vm]->vsyncend   ) &&
134                 ( vm_info.vtotal     == (s->vm_list)[vm]->vtotal     ))
135                 break;
136 
137         if ( vm >= s->vm_list_len ) {
138             fprintf( stderr,
139                 "Failed to find current video mode in server mode list\n" );
140             vm = -1;
141         }
142         return vm;
143     }
144 #endif
145 }
146 
147 
148 /**@BEGINFUNC**************************************************************
149 
150     Prototype  : void TVSCREENGetVidModeGeometry(
151                       TV_XSCREEN *s,
152                       int         vmode,
153                       Dimension  *width,
154                       Dimension  *height )
155 
156     Purpose    : Obtain the dimensions of the specified video mode.  Note
157                  that this may be different from the size of the desktop
158                  (i.e. the X Screen).
159 
160     Programmer : 16-Jan-99  Randall Hopper
161 
162     Parameters : s      - I: screen def struct
163                  vmode  - I: mode index
164                  width  - O: width  of video mode
165                  height - O: height of video mode
166 
167     Returns    : None.
168 
169     Globals    : None.
170 
171  **@ENDFUNC*****************************************************************/
172 
TVSCREENGetVidModeGeometry(TV_XSCREEN * s,int vmode,Dimension * width,Dimension * height)173 void TVSCREENGetVidModeGeometry(
174          TV_XSCREEN *s,
175          int         vmode,
176          Dimension  *width,
177          Dimension  *height )
178 {
179     if ( !s->vmode_ext_supported ) {
180         fprintf( stderr,
181                  "TVSCREENGetVidModeGeometry called without VidMode "
182                  "ext support\n" );
183         exit(1);
184     }
185 
186 #ifdef HAVE_XFREE86
187     *width  = (s->vm_list)[vmode]->hdisplay;
188     *height = (s->vm_list)[vmode]->vdisplay;
189 #endif
190 }
191 
192 
193 /**@BEGINFUNC**************************************************************
194 
195     Prototype  : void TVSCREENGetCurVidModeGeometry(
196                       TV_XSCREEN *s,
197                       Dimension  *width,
198                       Dimension  *height )
199 
200     Purpose    : Obtain the dimensions of the current video mode.  Note
201                  that this may be different from the size of the desktop
202                  (i.e. the X Screen).
203 
204     Programmer : 04-Oct-97  Randall Hopper
205 
206     Parameters : s      - I: screen def struct
207                  width  - O: width  of current video mode
208                  height - O: height of current video mode
209 
210     Returns    : None.
211 
212     Globals    : None.
213 
214  **@ENDFUNC*****************************************************************/
215 
TVSCREENGetCurVidModeGeometry(TV_XSCREEN * s,Dimension * width,Dimension * height)216 void TVSCREENGetCurVidModeGeometry(
217          TV_XSCREEN *s,
218          Dimension  *width,
219          Dimension  *height )
220 {
221     int vmode;
222 
223     if ( !s->vmode_ext_supported ) {
224         fprintf( stderr,
225                  "TVSCREENGetCurVidModeGeometry called without VidMode "
226                  "ext support\n" );
227         exit(1);
228     }
229 
230 #ifdef HAVE_XFREE86
231     vmode = TVSCREENGetCurVidMode( s );
232 
233     TVSCREENGetVidModeGeometry( s, vmode, width, height );
234 #endif
235 }
236 
237 
238 /**@BEGINFUNC**************************************************************
239 
240     Prototype  : static INT32 TVSCREENClosestVidMode(
241                       TV_XSCREEN *s,
242                       Dimension   width,
243                       Dimension   height )
244 
245     Purpose    : Returns the index of the closest video mode in
246                  s->vm_list to the specified resolution.
247 
248                  NOTE:  This call assumes the XFree Video Mode extension
249                  is supported.  If not, it returns -1.
250 
251     Programmer : 13-Apr-97  Randall Hopper
252 
253     Parameters : s      - I: screen def struct
254                  width  - I: target width
255                  height - I: target height
256 
257     Returns    : On success, index into s->vm_list
258                  On failure, -1
259                    (XF86 video mode extension not supported, or no
260                    applicable video mode)
261 
262     Globals    : None.
263 
264  **@ENDFUNC*****************************************************************/
265 
TVSCREENClosestVidMode(TV_XSCREEN * s,Dimension width,Dimension height)266 static TV_INT32 TVSCREENClosestVidMode(
267                     TV_XSCREEN *s,
268                     Dimension   width,
269                     Dimension   height )
270 {
271     if ( !s->vmode_ext_supported )
272         return -1;
273 
274 #ifdef HAVE_XFREE86
275     {
276         INT32                i,
277                              closest = -1,
278                              delta   = -1;
279         XF86VidModeModeInfo *vm_info;
280 
281         for ( i = 0; i < s->vm_list_len; i++ ) {
282             vm_info = (s->vm_list)[i];
283 
284             if (( vm_info->hdisplay >= width  ) &&
285                 ( vm_info->vdisplay >= height )) {
286                 if (( closest < 0 ) || ( vm_info->hdisplay - width < delta )) {
287                     closest = i;
288                     delta   = vm_info->hdisplay - width;
289                 }
290             }
291         }
292         return closest;
293     }
294 #endif
295 }
296 
297 
298 /**@BEGINFUNC**************************************************************
299 
300     Prototype  : static Boolean TVSCREENGetVisualDirectCap(
301                       TV_XSCREEN  *s,
302                       XVisualInfo *v,
303                       XVisualInfo *def_v )
304 
305     Purpose    : Determine whether or not direct video is supported for
306                  the specified visual.
307 
308     Programmer : 02-Mar-97  Randall Hopper
309 
310     Parameters : s     - I: screen def with VideoLL fields filled in
311                  v     - I: visual to analyze
312                  def_v - I: default visual of screen
313 
314     Returns    : T = direct video supported; F = not supported
315 
316     Globals    : None.
317 
318  **@ENDFUNC*****************************************************************/
319 
TVSCREENGetVisualDirectCap(TV_XSCREEN * s,XVisualInfo * v,XVisualInfo * def_v)320 static Boolean TVSCREENGetVisualDirectCap(
321                    TV_XSCREEN  *s,
322                    XVisualInfo *v,
323                    XVisualInfo *def_v )
324 {
325     TV_CAPTURE         *c = &G_glob.capture;
326     TV_PIXEL_GEOM       pix_geom;
327     TV_INT32            idx;
328     TV_BOOL             swap_b, swap_s;
329 
330     /*  Direct transfer is an option if:                                */
331     /*    1) linearly mapped frame buffer,                              */
332     /*    2) visual matches screen's default visual, &                  */
333     /*    3) capture card supports direct transfer for this visual.     */
334     /*    FIXME: Consider beefing up #3 for general 16bpp and           */
335     /*           pseudocolor at some point.                             */
336     if (( s->base_addr != 0 ) &&
337         ( s->bank_size >= s->ram_size ) &&
338         ( v->visualid == def_v->visualid ) &&
339         ( v->class == TrueColor )) {
340 
341     memset( &pix_geom, '\0', sizeof( pix_geom ) );
342     pix_geom.type     = TV_PIXELTYPE_RGB;
343         XUTILGetVisualBpp( TVDISPLAY, v, NULL, &pix_geom.Bpp );
344     pix_geom.mask[0]  = v->red_mask;
345     pix_geom.mask[1]  = v->green_mask;
346     pix_geom.mask[2]  = v->blue_mask;
347 
348         XUTILGetVisualSwaps( TVDISPLAY, v, &swap_b, &swap_s );
349     pix_geom.swap_bytes  = swap_b;
350     pix_geom.swap_shorts = swap_s;
351 
352     TVCAPTUREGetPixFmtByPixGeom( c, &pix_geom, &idx );
353 
354     if ( idx < 0 )
355       return False;
356     else
357       return True;
358     }
359     else
360       return False;
361 }
362 
363 
364 /**@BEGINFUNC**************************************************************
365 
366     Prototype  : static void TVSCREENAtExit()
367 
368     Purpose    : Deactivate zoom on exit (back to right vid mode).
369 
370     Programmer : 04-Nov-97  Randall Hopper
371 
372     Parameters : None.
373 
374     Returns    : None.
375 
376     Globals    : None.
377 
378  **@ENDFUNC*****************************************************************/
379 
TVSCREENAtExit()380 static void TVSCREENAtExit()
381 {
382     if ( !G_in_x_error )
383         TVSCREENSetZoomState( FALSE, FALSE );
384 }
385 
386 
387 /**@BEGINFUNC**************************************************************
388 
389     Prototype  : void TVSCREENInit(
390                       TV_XSCREEN *s,
391                       Display    *display,
392                       int         screen )
393 
394     Purpose    : Initialize the screen structure with the capabilities of
395                  the video card, server, and display driver.
396 
397     Programmer : 02-Mar-97  Randall Hopper
398 
399     Parameters : s       - I/O: Screen definition structure
400                  display - I: X display
401                  screen  - I: X screen number
402 
403     Returns    : None.
404 
405     Globals    : G_tvscreen
406 
407  **@ENDFUNC*****************************************************************/
408 
TVSCREENInit(TV_XSCREEN * s,Display * display,int screen)409 void TVSCREENInit( TV_XSCREEN *s,
410                    Display    *display,
411                    int         screen )
412 {
413     int                  shm_majv,
414                          shm_minv,
415                          dga_majv,
416                          dga_minv;
417     Bool                 shm_pixmaps;
418     XVisualInfo          vinfo_pref;
419     TV_INT32             i,
420                          rank,
421                          best_i,
422                          best_rank;
423     TV_TRANSFER_MODE     modes;
424     int                  vmode_ev_base,
425                          vmode_err_base,
426                          dga_flags_sup;
427     Bool                 ret;
428     TV_BOOL              dga_avail,
429                          vmode_avail;
430     char               **ext_list;
431     int                  ext_count,
432                          ext;
433 #if defined(HAVE_XFREE86) && defined(TESTING)
434     XF86VidModeMonitor   monitor;
435 #endif
436 
437     s->display     = display;
438     s->screen      = screen;
439 
440     /*  Until we get an enhanced DGA 2.0 to tell us, assume the frame      */
441     /*    buffer visual is the one with the biggest and badest pixel fmt.  */
442     XUTILDetermineFrameBufferVisual( s->display, s->screen, &s->fb_visual );
443 
444     /*  Dump some info about the X server itself  */
445     SUPRINTF(( "\nXSERVER: '%s' v%d,  Protocol Verson %d.%d\n",
446                ServerVendor(display), VendorRelease(display),
447                ProtocolVersion(display), ProtocolRevision(display) ));
448     SUPRINTF(( "         Screen Res = %dx%d, DefDepth = %d; "
449                         "NumScreens = %d\n",
450                DisplayWidth ( display, screen ),
451                DisplayHeight( display, screen ),
452                DefaultDepth ( display, screen ),
453                ScreenCount  ( display ) ));
454     SUPRINTF(( "         Bitmap Unit/BitOrder/Pad = %d/%s/%d, "
455                         "Image ByteOrder = %s\n",
456                BitmapUnit    ( display ),
457                BitmapBitOrder( display ) == LSBFirst ? "LSBFirst" : "MSBFirst",
458                BitmapPad     ( display ),
459                ImageByteOrder( display ) == LSBFirst ? "LSBFirst" : "MSBFirst"
460             ));
461     SUPRINTF(( "\n" ));
462 
463     /*  Get list of supported server extensions  */
464     ext_list = XListExtensions( TVDISPLAY, &ext_count );
465 
466     /*  Ok, now see what card capabilities we've got to play with here  */
467     modes = TV_TRANSFER_STD_IMAGE;
468 
469     /*  Shared memory extension (TRANSFER_SHMEM_{IMAGE,PIXMAP})  */
470     if ( !XUTILXServerIsLocal( TVDISPLAY ) )
471         SUPRINTF(( "Shm Extension not available...X Server isn't local.\n" ));
472     else if ( XShmQueryVersion( s->display, &shm_majv,
473                            &shm_minv, &shm_pixmaps ) == True ) {
474         modes |= TV_TRANSFER_SHMEM_IMAGE;
475         if ( shm_pixmaps )
476             modes |= TV_TRANSFER_SHMEM_PIXMAP;
477     }
478 
479     /*  Linear frame buf? (TRANSFER_DIRECT)  */
480     dga_avail = FALSE;
481 
482 #ifdef HAVE_XFREE86
483     if ( App_res.disable_direct_v )
484         SUPRINTF(( "Will not init DGA since -disableDirectV was given.\n" ));
485     else
486     if ( !XUTILXServerIsLocal( TVDISPLAY ) )
487         SUPRINTF(( "XF86DGA not available...X Server isn't local.\n" ));
488     else {
489         for ( ext = 0; ext < ext_count; ext++ )
490             if ( strcmp( ext_list[ext], XF86DGANAME ) )
491                  break;
492         if ( ext < ext_count )
493             dga_avail = TRUE;
494         else
495             SUPRINTF(( "XF86DGA extension not found\n" ));
496     }
497 
498     if ( dga_avail ) {
499         ret = XF86DGAQueryVersion( s->display, &dga_majv, &dga_minv );
500         if ( ret == True )
501             ret = XF86DGAQueryDirectVideo( s->display, s->screen,
502                                            &dga_flags_sup );
503 
504         if ( ret == False ) {
505             SUPRINTF(( "XF86DGA{QueryVersion,QueryDirectVideo}() failed\n" ));
506             dga_avail = FALSE;
507         }
508         else if ( !( dga_flags_sup & XF86DGADirectPresent ) ) {
509             SUPRINTF(( "XF86DGAQueryDirectVideo() reports DGA not avail\n" ));
510             dga_avail = FALSE;
511         }
512         else {
513             SUPRINTF(( "XF86DGAQueryVersion() succeeded - vers = %d.%.2d\n",
514                        dga_majv, dga_minv ));
515 
516             XF86DGAGetVideoLL( s->display, s->screen,
517                                (int *) &s->base_addr,
518                                (int *) &s->pitch,
519                                (int *) &s->bank_size,
520                                (int *) &s->ram_size );
521             s->ram_size *= 1024;
522 
523             SUPRINTF(( "   BaseAddr = 0x%lx, Pitch = %ld, "
524                           "BankSize/RamSize = %ld/%ld\n",
525                        s->base_addr, s->pitch, s->bank_size, s->ram_size ));
526         }
527     }
528 #endif
529 
530     if ( !dga_avail ) {
531         s->base_addr  = 0;
532         s->pitch      = 0;
533         s->bank_size  = 0;
534         s->ram_size   = 0;
535     }
536     s->dga_ext_supported = dga_avail;
537 
538     /*  Get a list of all visuals on our screen  */
539     vinfo_pref.screen = s->screen;
540     s->visual = XGetVisualInfo( s->display, VisualScreenMask, &vinfo_pref,
541                                 (int *) &s->num_visuals );
542     if ( s->num_visuals == 0 ) {
543         fprintf( stderr, "XGetVisualInfo() says no visuals available!\n" );
544         exit(1);
545     }
546 
547     if ( (s->visual_modes = calloc( s->num_visuals,
548                                     sizeof(TV_TRANSFER_MODE) )) == NULL )
549         TVUTILOutOfMemory();
550 
551     /*  Default to a visual that supports direct video, if possible (the    */
552     /*    deeper the better).  If not available, take any TrueColor         */
553     /*    visual.  If none, then we'll just hafta make due with             */
554     /*    Pseudocolor/GrayScale.                                            */
555     /*    NOTE: StaticColor, StaticGray, and DirectColor not supported now. */
556     /*  Also update visual "valid modes" mask while we're at it.            */
557     best_i    = -1;
558     best_rank = -1;
559     SUPRINTF(( "\nRating Available Visuals:\n"
560        "   Rating  Class        bpp  Bpp  R,G,B Masks                   "
561        "Swap  DirectVid\n"
562        "   ------  -----------  ---  ---  ----------------------------  "
563        "----  ---------\n"
564     ));
565     for ( i = 0; i < s->num_visuals; i++ ) {
566         XVisualInfo *v    = &s->visual[i];
567         TV_INT32     Bpp_pixmap,
568                      Bpp_fbuffer;
569         TV_BOOL      direct_v;
570 
571         XUTILGetVisualBpp( TVDISPLAY, v, &Bpp_pixmap, &Bpp_fbuffer );
572 
573         s->visual_modes[i] = modes;
574         if ( TVSCREENGetVisualDirectCap( s, v, s->fb_visual ) )
575             s->visual_modes[i] |= TV_TRANSFER_DIRECT;
576 
577         direct_v = ( s->visual_modes[i] & TV_TRANSFER_DIRECT ) != 0;
578 
579         /*  Rank this visual  */
580         switch ( v->class ) {
581             case TrueColor   :
582                 switch ( v->depth ) {
583                     case 32 :
584                     case 24 : if ( direct_v )
585                                   rank = 7;
586                               else
587                                   rank = 4;
588                               break;
589                     case 15 : rank = 5; break;
590                     case 16 : if ( direct_v )
591                                   rank = 5;
592                               else
593                                   rank = 4;
594                               break;
595                     default : /*  FIXME:  Ignore 8-bit true-color for now  */
596                               rank = ( v->depth <= 8 ) ? 0 : 3;
597                               break;
598                 }
599                 break;
600 
601             case PseudoColor : rank = 2;  break;
602             case GrayScale   : rank = 1;  break;
603 
604             case StaticGray  :
605             case StaticColor :
606             case DirectColor :
607             default          : rank = 0;
608                                break;
609         }
610 
611         /*  Is this the best so far?  */
612         if ( rank > best_rank )
613             best_i = i, best_rank = rank;
614 
615         /*  FIXME:  Handle byte swapping  */
616         SUPRINTF((
617            "   %3ld     %-11s   %2d  %1ld,%1ld  %.8lx, %.8lx, %.8lx   "
618            "--      %-3s\n",
619            rank, visual_classes[ v->class ], v->depth, Bpp_pixmap, Bpp_fbuffer,
620            v->red_mask, v->green_mask, v->blue_mask,
621            ( direct_v ? "Yes" : "No" ) ));
622     }
623     if ( best_rank <= 0 ) {
624         fprintf( stderr, "No supported visual found\n" );
625         exit(1);
626     }
627 
628     s->active_visual = best_i;
629     SUPRINTF(( "Chosen Visual is %d-bpp %s\n\n",
630                s->visual[ s->active_visual ].depth,
631                visual_classes[ s->visual[ s->active_visual ].class ] ));
632 
633     /*  Query for VidMode Extension  */
634     s->vmode_ext_supported = False;
635 
636     vmode_avail = FALSE;
637 
638 #ifdef HAVE_XFREE86
639     if ( !XUTILXServerIsLocal( TVDISPLAY ) )
640         SUPRINTF(( "XF86VidMode probably isn't enabled, if even available..."
641                    "X Server isn't local.\n" ));
642     else {
643         for ( ext = 0; ext < ext_count; ext++ )
644             if ( strcmp( ext_list[ext], XF86VIDMODENAME ) )
645                  break;
646         if ( ext < ext_count )
647             vmode_avail = TRUE;
648         else
649             SUPRINTF(( "XF86VidMode extension not found\n" ));
650     }
651 
652     if ( vmode_avail ) {
653         if ( !XF86VidModeQueryVersion( s->display, &s->vmode_majv,
654                                                    &s->vmode_minv ) )
655             SUPRINTF(( "XF86VidModeQueryVersion() failed\n" ));
656         else if ( !VERS_SAME_OR_NEWER( s->vmode_majv, s->vmode_minv,
657                                    VMODE_EXT_MIN_MAJOR, VMODE_EXT_MIN_MINOR ) )
658             SUPRINTF(( "XF86VidMode extension to old.  "
659                        "Its version %d.%.2d; we need >= %d.%.2d\n",
660                        s->vmode_majv, s->vmode_minv,
661                        VMODE_EXT_MIN_MAJOR, VMODE_EXT_MIN_MINOR ));
662         else if ( !XF86VidModeQueryExtension( s->display, &vmode_ev_base,
663                                               &vmode_err_base ) )
664             SUPRINTF(( "XF86VidModeQueryExtension() failed\n" ));
665         else {
666             s->vmode_ext_supported = True;
667 
668             SUPRINTF((
669                 "XF86VidModeQueryVersion() succeeded - version = %d.%.2d\n",
670                 s->vmode_majv, s->vmode_minv ));
671 
672 #  ifdef TESTING
673             /*  Dump monitor info  */
674             if ( XF86VidModeGetMonitor( s->display, s->screen, &monitor ) ) {
675                 SUPRINTF(( "\nMonitor: %s %s\n",
676                            monitor.vendor, monitor.model ));
677             }
678 #  endif
679 
680             /*  Query all available video modes  */
681             XF86VidModeGetAllModeLines( s->display, s->screen, &s->vm_list_len,
682                                         &s->vm_list );
683 
684             s->vm_startup = TVSCREENGetCurVidMode( s );
685             if ( s->vm_startup < 0 )
686                 s->vmode_ext_supported = False;
687         }
688     }
689 #endif
690 
691     /*  Hook in handler to deactivate zoom on exit  */
692     atexit( TVSCREENAtExit );
693 
694     /*  FIXME:  Other things it'd be good if we could print out when  */
695     /*    "startup" debugs are enabled (SUPRINTF):                    */
696     /*      -  Graphics card                                          */
697     /*      -  X Server (SVGA,S3V,etc.)                               */
698     /*      -  "startx -- -probeonly" output                          */
699     /*      -  "appres Fxtv" output                                   */
700 }
701 
702 
703 /**@BEGINFUNC**************************************************************
704 
705     Prototype  : static TV_TRANSFER_MODE TVSCREENDetermineTransferMode(
706                       TV_DISPLAY       *d,
707                       TV_CAPTURE_MODE   cap_mode )
708 
709     Purpose    : Determines the appropriate transfer mode to use for
710                  starting a capture using the specified capture mode.
711 
712                  This rtn takes into account the detected capabilities of
713                  the display system and capture driver, as well as the
714                  current state of the display system (e.g. whether the
715                  video window is unoccluded or not).
716 
717     Programmer : 08-Oct-97  Randall Hopper
718 
719     Parameters : d        - I: display def struct
720                  cap_mode - I: desired capture mode (SINGLE or CONTINUOUS)
721 
722     Returns    : transfer_mode to use for capture
723 
724     Globals    : None.
725 
726  **@ENDFUNC*****************************************************************/
727 
TVSCREENDetermineTransferMode(TV_DISPLAY * d,TV_CAPTURE_MODE cap_mode)728 static TV_TRANSFER_MODE TVSCREENDetermineTransferMode(
729                             TV_DISPLAY       *d,
730                             TV_CAPTURE_MODE   cap_mode )
731 {
732     static TV_BOOL    S_done_no_dv_msg = FALSE;
733 
734     TV_XSCREEN       *x = &G_glob.x;
735     TV_TRANSFER_MODE  transfer_mode = 0;
736     TV_BOOL           dirvid_sup,
737                       shimg_sup;
738 
739     dirvid_sup = x->visual_modes[ x->active_visual ] & TV_TRANSFER_DIRECT;
740     shimg_sup  = x->visual_modes[ x->active_visual ] & TV_TRANSFER_SHMEM_IMAGE;
741 
742     /*  For SINGLE capture mode...  */
743     if ( cap_mode == TV_CAPTURE_SINGLE ) {
744         if ( shimg_sup )
745             transfer_mode = TV_TRANSFER_SHMEM_IMAGE;
746         else
747             transfer_mode = TV_TRANSFER_STD_IMAGE;
748     }
749 
750     /*  For CONTINUOUS capture mode...  */
751     else {
752         TV_BOOL set = FALSE;
753 
754         if ( !App_res.disable_direct_v &&
755              ( d->win_visibility == VisibilityUnobscured ) ) {
756             if ( dirvid_sup ) {
757                 transfer_mode = TV_TRANSFER_DIRECT;
758                 set           = TRUE;
759             }
760 #ifdef HAVE_XFREE86
761             else if ( !S_done_no_dv_msg ) {
762                 fprintf( stderr,
763                      "Direct Video not supported by visual...using XImages\n");
764                 S_done_no_dv_msg = TRUE;
765             }
766 #endif
767         }
768 
769         if ( !set )
770             if ( shimg_sup )
771                 transfer_mode = TV_TRANSFER_SHMEM_IMAGE;
772             else
773                 transfer_mode = TV_TRANSFER_STD_IMAGE;
774     }
775 
776     assert( transfer_mode );
777     return transfer_mode;
778 }
779 
780 
781 /**@BEGINFUNC**************************************************************
782 
783     Prototype  : static void TVSCREENGetWinRootGeometry(
784                       Window   win,
785                       TV_GEOM  in,
786                       TV_GEOM *out )
787 
788     Purpose    : Translates window coordinates to the root window.
789 
790     Programmer : 04-Mar-97  Randall Hopper
791 
792     Parameters : win - I: window
793                  in  - I: coords rel to win
794                  out - O: coords rel to root window
795 
796     Returns    : None.
797 
798     Globals    : None.
799 
800  **@ENDFUNC*****************************************************************/
801 
TVSCREENWinGeometryToRoot(Window win,TV_GEOM in,TV_GEOM * out)802 static void TVSCREENWinGeometryToRoot(
803                 Window   win,
804                 TV_GEOM  in,
805                 TV_GEOM *out )
806 {
807     Window child_win;
808     int    root_x,
809            root_y;
810 
811     if ( !XTranslateCoordinates( TVDISPLAY, win,
812                                  RootWindow( TVDISPLAY, TVSCREEN ),
813                                  in.x, in.y,
814                                  &root_x, &root_y, &child_win ) ) {
815         fprintf( stderr, "XTranslateCoordinates() failed\n" );
816         exit(1);
817     }
818 
819     out->x = root_x;
820     out->y = root_y;
821     out->w = in.w;
822     out->h = in.h;
823 }
824 
825 
826 /**@BEGINFUNC**************************************************************
827 
828     Prototype  : static void TVSCREENGetWinGeometry(
829                       Window   win,
830                       TV_GEOM *g,
831                       TV_BOOL     reget )
832 
833     Purpose    : Return the geometry of the specified window.
834 
835     Programmer : 04-Mar-97  Randall Hopper
836 
837     Parameters : win - I:   window
838                  g   - O:   window coords
839 
840     Returns    : None.
841 
842     Globals    : None.
843 
844  **@ENDFUNC*****************************************************************/
845 
TVSCREENGetWinGeometry(Window win,TV_GEOM * g)846 static void TVSCREENGetWinGeometry(
847                 Window   win,
848                 TV_GEOM *g )
849 {
850     XWindowAttributes  xwa;
851 
852     XGetWindowAttributes( TVDISPLAY, win, &xwa );
853 
854     g->x = 0;
855     g->y = 0;
856     g->w = xwa.width;
857     g->h = xwa.height;
858 }
859 
860 
861 /**@BEGINFUNC**************************************************************
862 
863     Prototype  : void TVSCREENUpdateWinGeometry()
864 
865     Purpose    : Called whenever the location of our video window (relative
866                  to the root window) could have changed.
867 
868                  We must keep this up-to-date when running in direct video
869                  since this information is used to compute the driver
870                  capture parameters for frame transfer into video memory.
871 
872     Programmer : 06-Oct-97  Randall Hopper
873 
874     Parameters : None.
875 
876     Returns    : None.
877 
878     Globals    : None.
879 
880  **@ENDFUNC*****************************************************************/
881 
TVSCREENUpdateWinGeometry()882 void TVSCREENUpdateWinGeometry()
883 {
884     TV_DISPLAY        *d = &G_glob.display;
885 
886     /*  First, update the video win geom relative to the root window  */
887     TVSCREENGetWinGeometry( d->win, &d->geom );
888     TVSCREENWinGeometryToRoot( d->win, d->geom, &d->geom );
889 
890     /*  And also update the refresh region relative to the root window.    */
891     /*   This region includes all the widgets on the same top-level shell  */
892     /*   as the video window to clean up any stray video droppings while   */
893     /*   moving the video window in direct video mode.                     */
894     if ( !XtIsRealized( d->shell_wgt ) )
895         memcpy( &d->refresh_geom, &d->geom, sizeof( d->refresh_geom ) );
896     else {
897         Window win = XtWindow( d->shell_wgt );
898 
899         TVSCREENGetWinGeometry( win, &d->refresh_geom );
900         TVSCREENWinGeometryToRoot( win, d->refresh_geom, &d->refresh_geom );
901 
902         /*  Add a little slack  */
903         d->refresh_geom.x -=   REFRESH_SLACK_PIXELS;
904         d->refresh_geom.y -=   REFRESH_SLACK_PIXELS;
905         d->refresh_geom.w += 2*REFRESH_SLACK_PIXELS;
906         d->refresh_geom.h += 2*REFRESH_SLACK_PIXELS;
907     }
908 }
909 
910 
911 /**@BEGINFUNC**************************************************************
912 
913     Prototype  : static void TVSCREENGetCapturePixGeom(
914                       TV_XSCREEN    *s,
915                       TV_BOOL        direct_vid,
916                       TV_PIXEL_GEOM *pix_geom )
917 
918     Purpose    : Populate the passed pix_geom structure with info from
919                  the active visual.
920 
921     Programmer : 30-Mar-97  Randall Hopper
922 
923     Parameters : d        - I: display def struct
924                  pix_geom - O: pixel geometry for the visual
925 
926 
927     Returns    : None.
928 
929     Globals    : None.
930 
931  **@ENDFUNC*****************************************************************/
932 
TVSCREENGetCapturePixGeom(TV_XSCREEN * s,TV_BOOL direct_vid,TV_PIXEL_GEOM * pix_geom)933 static void TVSCREENGetCapturePixGeom( TV_XSCREEN    *s,
934                                        TV_BOOL        direct_vid,
935                                        TV_PIXEL_GEOM *pix_geom )
936 {
937     TV_CAPTURE        *c = &G_glob.capture;
938     TV_BOOL            swap_b,
939                        swap_s;
940     TV_INT32           idx,
941                        Bpp_pixmap,
942                        Bpp_fbuffer;
943 
944     XVisualInfo *v = &s->visual[ s->active_visual ];
945 
946     pix_geom->type = TV_PIXELTYPE_RGB;
947 
948     /*  Our first pick is the pixel geometry of the visual  */
949     if ( v->class == TrueColor ) {
950         XUTILGetVisualBpp( TVDISPLAY, v, &Bpp_pixmap, &Bpp_fbuffer );
951 
952         pix_geom->Bpp     = (direct_vid ? Bpp_fbuffer : Bpp_pixmap );
953         pix_geom->mask[0] = v->red_mask;
954         pix_geom->mask[1] = v->green_mask;
955         pix_geom->mask[2] = v->blue_mask;
956 
957         if ( direct_vid )
958             XUTILGetVisualSwaps( TVDISPLAY, v, &swap_b, &swap_s );
959         else {
960             swap_b = ( ImageByteOrder( TVDISPLAY ) == LSBFirst );
961             swap_s = ( ImageByteOrder( TVDISPLAY ) == LSBFirst ) &&
962                      ( pix_geom->Bpp >= 4 );
963         }
964 
965         pix_geom->swap_bytes  = swap_b;
966         pix_geom->swap_shorts = swap_s;
967     }
968     else {
969         /*  For e.g. 8bpp PseudoColor  */
970         pix_geom->Bpp     = 2;
971         pix_geom->mask[0] = 0x7C00;
972         pix_geom->mask[1] = 0x03E0;
973         pix_geom->mask[2] = 0x001F;
974 
975         pix_geom->swap_bytes  = 1;
976         pix_geom->swap_shorts = 0;
977     }
978 
979     TVCAPTUREGetPixFmtByPixGeom( c, pix_geom, &idx );
980 
981     if ( idx >= 0 )
982         TVCAPTUREGetNthPixFmt( c, idx, pix_geom );
983 
984     /*  If its not supported by the capture hardware, just find something  */
985     /*    reasonable and we'll convert it on the CPU.                      */
986     else {
987         TV_PIXEL_GEOM pg,
988                       best_pg;
989         TV_UINT32     i,
990                       best_i = -1,
991                       num_pg;
992         TV_BOOL       take_it;
993 
994         TVCAPTUREGetNumPixFmts( c, &num_pg );
995         for ( i = 0; i < num_pg; i++ ) {
996             TVCAPTUREGetNthPixFmt( c, i, &pg );
997             take_it = False;
998 
999             /*  Never take a non-RGB format (e.g. YUV)  */
1000             if ( pg.type != TV_PIXELTYPE_RGB )
1001                 take_it = False;
1002 
1003             /*  Grab it if we don't have a pick yet  */
1004             else if ( best_i < 0 )
1005                 take_it = True;
1006 
1007             /*  Prefer 2Bpp byte swapped over the rest (since its the  */
1008             /*    thing NewFrameHdlr currently byte swaps well).       */
1009             else if (( best_pg.Bpp != 2 ) || !best_pg.swap_bytes )
1010                 if  (( pg.Bpp      == 2 ) &&  pg.swap_bytes      )
1011                     take_it = True;
1012                 else if ( pg.Bpp == 2 )
1013                     take_it = True;
1014 
1015             if ( take_it ) {
1016                 best_i          = i;
1017                 best_pg         = pg;
1018             }
1019         }
1020         *pix_geom = best_pg;
1021     }
1022 }
1023 
1024 
1025 /**@BEGINFUNC**************************************************************
1026 
1027     Prototype  : static void TVSCREENUpdateRootRegion(
1028                       TV_GEOM      g,
1029                       XtAppContext app_context )
1030 
1031     Purpose    : Forces a redraw of a particular region of the root
1032                  window.
1033 
1034     Programmer : 04-Mar-97  Randall Hopper
1035 
1036     Parameters : g           - I: the region to update (rel to root win)
1037                  app_context - I: the application context
1038 
1039     Returns    : None.
1040 
1041     Globals    : None.
1042 
1043  **@ENDFUNC*****************************************************************/
1044 
TVSCREENUpdateRootRegion(TV_GEOM g,XtAppContext app_context)1045 static void TVSCREENUpdateRootRegion(
1046                 TV_GEOM      g,
1047                 XtAppContext app_context )
1048 {
1049     static Window        refresh_win = None;
1050 
1051 #ifdef WE_DONT_NEED_TO_WAIT_FOR_MAP
1052     XEvent               ev;
1053 #endif
1054     XSetWindowAttributes xswa;
1055 
1056     /*  There's doubtless a better way to do this; XSendEventing an expose  */
1057     /*    to the root window didn't work.                                   */
1058     /*  FIXME:  Don't create new win each time; cache and just reconfigure  */
1059     /*          for each use.                                               */
1060     xswa.override_redirect = True;
1061     if ( refresh_win == None ) {
1062         refresh_win = XCreateWindow( TVDISPLAY, DefaultRootWindow(TVDISPLAY),
1063                          g.x, g.y, g.w, g.h, 0,
1064                          CopyFromParent, InputOutput, CopyFromParent,
1065                          CWOverrideRedirect, &xswa );
1066         XSelectInput( TVDISPLAY, refresh_win, StructureNotifyMask );
1067     }
1068     else
1069         XMoveResizeWindow( TVDISPLAY, refresh_win, g.x, g.y, g.w, g.h );
1070 
1071     XMapWindow  ( TVDISPLAY, refresh_win );
1072     XRaiseWindow( TVDISPLAY, refresh_win );
1073 
1074 #ifdef WE_DONT_NEED_TO_WAIT_FOR_MAP
1075     /* Wait for map. */
1076     while(1) {
1077         XtAppNextEvent( app_context, &ev );
1078         /* XNextEvent( TVDISPLAY, &ev );  */
1079 
1080         if ( ev.type == MapNotify && ev.xmap.event == refresh_win )
1081             break;
1082 
1083         XtDispatchEvent( &ev );
1084     }
1085 #endif
1086 
1087     XSync( TVDISPLAY, False );
1088 
1089     XUnmapWindow( TVDISPLAY, refresh_win );
1090     XSync( TVDISPLAY, False );
1091 }
1092 
1093 
1094 /**@BEGINFUNC**************************************************************
1095 
1096     Prototype  : void TVSCREENRedrawVideoWin()
1097 
1098     Purpose    : If capture is stopped and the saved XImage looks
1099                  reasonable, blast it back up in the video window.
1100 
1101     Programmer : 08-Mar-97  Randall Hopper
1102 
1103     Parameters : None.
1104 
1105     Returns    : None.
1106 
1107     Globals    : None.
1108 
1109  **@ENDFUNC*****************************************************************/
1110 
TVSCREENRedrawVideoWin()1111 void TVSCREENRedrawVideoWin()
1112 {
1113     TV_DISPLAY        *d = &G_glob.display;
1114     TV_CAPTURE        *c = &G_glob.capture;
1115     TV_XSCREEN        *x = &G_glob.x;
1116 
1117     if ( d->win == None )
1118         return;
1119 
1120     /*  Draw the latest Image in the video window  */
1121     if ( d->enabled && d->ximage_use_for_expose &&
1122          ( d->ximage.ximg   != NULL ) &&
1123          ( d->ximage.geom.w == d->geom.w ) &&
1124          ( d->ximage.geom.h == d->geom.h ) &&
1125          ( d->ximage.visual == &x->visual[ x->active_visual ] ) ) {
1126 
1127         if ( d->ximage.is_shm )
1128             XShmPutImage( TVDISPLAY, d->win, d->gc, d->ximage.ximg,
1129                           0, 0, 0, 0, d->ximage.geom.w, d->ximage.geom.h,
1130                           False );
1131         else
1132             XPutImage   ( TVDISPLAY, d->win, d->gc, d->ximage.ximg,
1133                           0, 0, 0, 0, d->ximage.geom.w, d->ximage.geom.h );
1134     }
1135     else
1136         XClearWindow( TVDISPLAY, d->win );
1137 
1138     /*  Update any annotation that's active (if continuous capture is on). */
1139     /*    Note that this only affects ximages mode.                        */
1140     if ( c->cap_mode == TV_CAPTURE_CONTINUOUS )
1141         TVANNOTUpdate( &d->annot );
1142 
1143     XFlush( TVDISPLAY );
1144     /*XSync( TVDISPLAY, 0 );*/
1145 }
1146 
1147 /*  TVSCREENGetTransparentCursor - Build a totally transparent cursor  */
TVSCREENGetTransparentCursor()1148 static Cursor TVSCREENGetTransparentCursor()
1149 {
1150     static Cursor S_cursor = None;
1151 
1152     TV_DISPLAY        *d = &G_glob.display;
1153 
1154     if (( d->video_wgt == NULL ) || ( d->win == None )) {
1155         fprintf( stderr, "TVSCREENGetBlankCursor: Bad state\n" );
1156         exit(1);
1157     }
1158 
1159     if ( S_cursor == None ) {
1160         Pixmap             pix, pix_mask;
1161         XColor             white, black;
1162         GC                 gc;
1163         XGCValues          gcv;
1164         TV_INT32           size = CURSOR_SIZE;
1165 
1166         black.pixel = BlackPixel( TVDISPLAY, TVSCREEN );
1167         white.pixel = WhitePixel( TVDISPLAY, TVSCREEN );
1168         black.red = black.green = black.blue = 0x0000;
1169         white.red = white.green = white.blue = 0xFFFF;
1170 
1171         pix      = XCreatePixmap( TVDISPLAY, d->win, size, size, 1 );
1172         pix_mask = XCreatePixmap( TVDISPLAY, d->win, size, size, 1 );
1173 
1174         gcv.function   = GXclear;
1175         gcv.foreground = 1;
1176         gcv.background = 0;
1177         gc             = XCreateGC( TVDISPLAY, pix,
1178                             GCFunction | GCForeground | GCBackground,
1179                             &gcv );
1180 
1181         XFillRectangle( TVDISPLAY, pix     , gc, 0, 0, size, size );
1182         XFillRectangle( TVDISPLAY, pix_mask, gc, 0, 0, size, size );
1183 
1184         XFreeGC( TVDISPLAY, gc );
1185 
1186         S_cursor = XCreatePixmapCursor( TVDISPLAY, pix, pix_mask,
1187                                         &white, &black, size/2, size/2 );
1188     }
1189 
1190     return S_cursor;
1191 }
1192 
1193 
1194 /*  TVSCREENSetVideoWinCursorEnabled - Turn the cursor on the video  */
1195 /*    window on or off.                                              */
TVSCREENSetVideoWinCursorEnabled(TV_BOOL enable)1196 static void TVSCREENSetVideoWinCursorEnabled( TV_BOOL enable )
1197 {
1198     TV_DISPLAY        *d = &G_glob.display;
1199 
1200     if (( d->video_wgt == NULL ) || ( d->win == None ))
1201         return;
1202 
1203     if ( enable )
1204         XUndefineCursor( TVDISPLAY, d->win );
1205     else
1206         XDefineCursor( TVDISPLAY, d->win, TVSCREENGetTransparentCursor() );
1207 }
1208 
1209 
1210 /*  TVSCREENCursorTurnoffTimeoutCB - When this timeout expires, turn off  */
1211 /*    the cursor over the video window.                                   */
TVSCREENCursorTurnoffTimeoutCB(XtPointer cl_data,XtIntervalId * timer)1212 static void TVSCREENCursorTurnoffTimeoutCB(
1213          XtPointer          cl_data,
1214          XtIntervalId      *timer )
1215 {
1216     TV_DISPLAY      *d = &G_glob.display;
1217 
1218     d->cursor_timer_set = FALSE;
1219 
1220     if ( !d->cursor_dozeoff_enabled )
1221         return;
1222 
1223     TVSCREENSetVideoWinCursorEnabled( FALSE );
1224 }
1225 
1226 /*  TVSCREENWakeupCursor - If the cursor is off, turns it back on, and  */
1227 /*    restarts the "doze-off" timer.                                    */
TVSCREENWakeupCursor()1228 static void TVSCREENWakeupCursor()
1229 {
1230     TV_DISPLAY      *d = &G_glob.display;
1231 
1232     if ( !d->cursor_dozeoff_enabled )
1233         return;
1234 
1235     if ( !d->cursor_timer_set )
1236         TVSCREENSetVideoWinCursorEnabled( TRUE );
1237     else
1238         XtRemoveTimeOut( d->cursor_timer );
1239 
1240     d->cursor_timer = XtAppAddTimeOut( TVAPPCTX, CURSOR_TURNOFF_DELAY_MS,
1241                                        TVSCREENCursorTurnoffTimeoutCB, NULL );
1242     d->cursor_timer_set = TRUE;
1243 }
1244 
1245 
1246 /*  TVSCREENCapConfigure - convience wrapper for configuring the capture  */
1247 /*    subsystem for on-screen use.                                        */
TVSCREENCapConfigure(TV_CAPTURE_MODE cap_mode,char ** fail_reason)1248 static TV_BOOL TVSCREENCapConfigure(
1249                    TV_CAPTURE_MODE   cap_mode,
1250                    char            **fail_reason )
1251 {
1252     TV_CAPTURE      *c = &G_glob.capture;
1253     TV_DISPLAY      *d = &G_glob.display;
1254     TV_BOOL          ret,
1255                      do_frame_cb;
1256     TV_INT32         fps = App_res.display_fps;
1257     TV_TRANSFER_MODE transfer_mode;
1258 
1259     transfer_mode = TVSCREENDetermineTransferMode( d, cap_mode );
1260 
1261     do_frame_cb = (transfer_mode != TV_TRANSFER_DIRECT);
1262 
1263     TVCAPTURESetFrameDoneCBEnabled( c, do_frame_cb );
1264 
1265     /*  FIXME:  FPS doesnt work consistently in the driver yet.  With the    */
1266     /*    below hack, we'll capture full-speed to the driver buffer, though  */
1267     /*    we're only sampling one every 1/fps sec.                           */
1268 #ifdef DRIVER_FPS_BUG
1269     TVCAPTURESetFPS               ( c, c->fps_max );
1270 #else
1271     TVCAPTURESetFPS               ( c, fps );
1272 #endif
1273     TVSetWorkProcTimeout( do_frame_cb ? (1000/fps) : -1 );
1274 
1275     TVCAPTURESetCaptureMode ( c, d->cap_mode   );
1276     TVCAPTURESetTransferMode( c, transfer_mode );
1277     TVCAPTURESetRegionGeom  ( c, &d->geom      );
1278     TVCAPTURESetPixelGeom   ( c, &d->pix_geom  );
1279 
1280     ret = TVCAPTUREConfigure( c, fail_reason );
1281     return ret;
1282 }
1283 
1284 
1285 /**@BEGINFUNC**************************************************************
1286 
1287     Prototype  : void TVSCREENResetStartVideoTimer(
1288                       void )
1289 
1290     Purpose    : Clear any pending start request timer.  No-op if none set.
1291 
1292     Programmer : 06-Oct-97  Randall Hopper
1293 
1294     Parameters : None.
1295 
1296     Returns    : None.
1297 
1298     Globals    : None.
1299 
1300  **@ENDFUNC*****************************************************************/
1301 
TVSCREENResetStartVideoTimer(void)1302 void TVSCREENResetStartVideoTimer( void )
1303 {
1304     if ( S_restart_timer_set ) {
1305         XtRemoveTimeOut( S_restart_timer );
1306         S_restart_timer_set = False;
1307     }
1308 }
1309 
1310 
1311 /**@BEGINFUNC**************************************************************
1312 
1313     Prototype  : static void TVSCREENRestartVideoTimeoutCB(
1314                       XtPointer          cl_data,
1315                       XtIntervalId      *timer )
1316 
1317     Purpose    : Xt timer callback to restart video after a specific
1318                  number of milliseconds have passed.
1319 
1320                  See comment below in TVSCREENQueueStartRequest header
1321                  for illumination as to "why" this is even here.
1322 
1323     Programmer : 05-Mar-97  Randall Hopper
1324 
1325     Parameters : cl_data - I: not used
1326                  timer   - I: not used
1327 
1328     Returns    : None.
1329 
1330     Globals    : None.
1331 
1332  **@ENDFUNC*****************************************************************/
1333 
TVSCREENRestartVideoTimeoutCB(XtPointer cl_data,XtIntervalId * timer)1334 static void TVSCREENRestartVideoTimeoutCB(
1335          XtPointer          cl_data,
1336          XtIntervalId      *timer )
1337 {
1338     TV_DISPLAY        *d = &G_glob.display;
1339     TV_CAPTURE        *c = &G_glob.capture;
1340     TV_XSCREEN        *x = &G_glob.x;
1341     char              *cfg_fail_msg,
1342                       *xfer_str;
1343 
1344     S_restart_timer_set = False;
1345 
1346     TVSCREENUpdateWinGeometry();
1347     TVSCREENGetCapturePixGeom ( x, (c->xfer_mode == TV_TRANSFER_DIRECT),
1348                                 &d->pix_geom );
1349 
1350     /*  Reconfigure.  Note this may fail if new window geo  */
1351     /*    won't jive with hardware or driver capabilities.  */
1352     if ( !TVSCREENCapConfigure( d->cap_mode, &cfg_fail_msg ) ) {
1353         fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n", cfg_fail_msg );
1354         XClearWindow( TVDISPLAY, d->win );
1355         XBell( TVDISPLAY, 25 );
1356         return;
1357     }
1358 
1359     /*  When starting direct video, invalidate use of ximage for exposes.   */
1360     /*    Produces annoying flash when restacking window (redrawing region) */
1361     if ( c->xfer_mode == TV_TRANSFER_DIRECT )
1362         d->ximage_use_for_expose = FALSE;
1363 
1364     /*  Ready to go.  Set annotation update mode.  */
1365     TVANNOTSetAutoUpdateMode( &d->annot,
1366                               (( d->cap_mode  == TV_CAPTURE_CONTINUOUS ) &&
1367                                ( c->xfer_mode == TV_TRANSFER_DIRECT    )) );
1368 
1369     /*  Set cursor turn-off timer  */
1370     if ( d->cap_mode == TV_CAPTURE_CONTINUOUS ) {
1371         d->cursor_dozeoff_enabled = TRUE;
1372         TVSCREENWakeupCursor();
1373     }
1374 
1375     /*  Tell user what the transfer mode is going to be  */
1376     xfer_str = "";
1377     switch ( c->xfer_mode ) {
1378         case TV_TRANSFER_STD_IMAGE   : xfer_str = "Images"       ;  break;
1379         case TV_TRANSFER_SHMEM_IMAGE : xfer_str = "Shm Images"   ;  break;
1380         case TV_TRANSFER_DIRECT      : xfer_str = "Direct Video" ;  break;
1381         case TV_TRANSFER_SHMEM_PIXMAP: xfer_str = "Shm Pixmaps"  ;  break;
1382     }
1383     DRVPRINTF(( "TRANSFER MODE: %s\n", xfer_str ));
1384 
1385     /*  And fire it up  */
1386     TVCAPTUREStart( c );
1387 }
1388 
1389 
1390 /**@BEGINFUNC**************************************************************
1391 
1392     Prototype  : static void TVSCREENQueueStartRequest( void )
1393 
1394     Purpose    : This restart delay is a big hack for continuous
1395                  direct video mode.
1396 
1397                  Basically we need to allow all the visibility events to
1398                  flush from the last CAPTUREStop before we can initiate
1399                  another CAPTUREStart or we'll just be stopping again when
1400                  we get a Partial- or Total-Obscured notif (which will
1401                  itself cause more visibility notifications and we'll
1402                  just end up in a start/stop/start/stop... loop that
1403                  accomplishes nothing).
1404 
1405                  FIXME:  If there's a better way, change to doing it.
1406 
1407     Programmer : 05-Mar-97  Randall Hopper
1408 
1409     Parameters : None.
1410 
1411     Returns    : None.
1412 
1413     Globals    : None.
1414 
1415  **@ENDFUNC*****************************************************************/
1416 
TVSCREENQueueStartRequest(void)1417 static void TVSCREENQueueStartRequest( void )
1418 {
1419     TVSCREENResetStartVideoTimer();
1420 
1421     S_restart_timer = XtAppAddTimeOut( TVAPPCTX,
1422                                        DIRECTVID_RESTART_DELAY_MS,
1423                                        TVSCREENRestartVideoTimeoutCB, NULL );
1424     S_restart_timer_set = True;
1425 }
1426 
1427 
1428 /**@BEGINFUNC**************************************************************
1429 
1430     Prototype  : TV_BOOL TVSCREENVideoStarted(
1431                       void )
1432 
1433     Purpose    : Returns TRUE if video capture has been initiated via
1434                  TVSCREENStartVideo() and is pending or active.
1435 
1436     Programmer : 06-Oct-97  Randall Hopper
1437 
1438     Parameters : None.
1439 
1440     Returns    : TRUE - Capture is pending or active
1441 
1442     Globals    : None.
1443 
1444  **@ENDFUNC*****************************************************************/
1445 
TVSCREENVideoStarted(void)1446 TV_BOOL TVSCREENVideoStarted( void )
1447 {
1448     TV_CAPTURE        *c = &G_glob.capture;
1449 
1450     return ( S_restart_timer_set || c->contin_on );
1451 }
1452 
1453 
1454 /**@BEGINFUNC**************************************************************
1455 
1456     Prototype  : TV_BOOL TVSCREENVideoCapContin(
1457                       void )
1458 
1459     Purpose    : After a StartVideo request has been made, returns TRUE
1460                  if the configured capture mode for the transfer was
1461                  CONTINUOUS.
1462 
1463     Programmer : 06-Oct-97  Randall Hopper
1464 
1465     Parameters : None.
1466 
1467     Returns    : T if cap mode configured was CONTINUOUS
1468 
1469     Globals    : None.
1470 
1471  **@ENDFUNC*****************************************************************/
1472 
TVSCREENVideoReqCaptureContin(void)1473 TV_BOOL TVSCREENVideoReqCaptureContin( void )
1474 {
1475     TV_CAPTURE        *c = &G_glob.capture;
1476 
1477     /*  Calling this is an error if a capture isn't pending or active  */
1478     if ( !TVSCREENVideoStarted() ) {
1479         fprintf( stderr, "TVSCREENVideoReqCaptureContin called with no "
1480                          "capture pending or active\n" );
1481         exit(1);
1482     }
1483 
1484     return (c->cap_mode == TV_CAPTURE_CONTINUOUS);
1485 }
1486 
1487 
1488 
1489 /**@BEGINFUNC**************************************************************
1490 
1491     Prototype  : void TVSCREENStartVideo( void )
1492                  void TVSCREENStopVideo( TV_BOOL suppress_redraw )
1493 
1494     Purpose    : Convenience routines used to start and stop capture when
1495                  the video is being displayed on-screen.  Abstracts some
1496                  of the nastiness that has to happen for direct video.
1497 
1498                  Note:  suppress_refresh can be used to suppress the
1499                  forced expose/redraw of the video area when in direct
1500                  video mode.  This is useful when stopping video briefly
1501                  to capture a frame to XImage or to briefly stop to
1502                  reconfigure driver parameters.  Otherwise, the exposure
1503                  event causes a blit of the last-saved XImage up into the
1504                  window which is distracting.
1505 
1506     Programmer : 16-Mar-97  Randall Hopper
1507 
1508     Parameters : suppress_redraw - I: in direct video, suppress forced
1509                                       redraw of video window
1510 
1511     Returns    : None.
1512 
1513     Globals    : None.
1514 
1515  **@ENDFUNC*****************************************************************/
1516 
TVSCREENStartVideo(void)1517 void TVSCREENStartVideo( void )
1518 {
1519     TV_CAPTURE        *c = &G_glob.capture;
1520 
1521     /*  This is an error if a capture is pending or active.  */
1522     if ( S_restart_timer_set ) {
1523         fprintf( stderr, "TVSCREENStartVideo called with capture "
1524                          "already pending...ignored\n" );
1525         return;
1526     }
1527     if ( c->contin_on ) {
1528         fprintf( stderr, "TVSCREENStartVideo called with continous capture "
1529                          "already running...ignored\n" );
1530         return;
1531     }
1532 
1533     /*  All clear.  Queue a start request.  */
1534     TVSCREENQueueStartRequest();
1535 }
1536 
TVSCREENStopVideo(TV_BOOL suppress_redraw)1537 void TVSCREENStopVideo( TV_BOOL suppress_redraw )
1538 {
1539     TV_DISPLAY        *d = &G_glob.display;
1540     TV_CAPTURE        *c = &G_glob.capture;
1541     TV_GEOM            new_refresh_geom;
1542     Window             shell_win;
1543 
1544     /*  This is an error if no capture is pending or active.  */
1545     if ( S_restart_timer_set )
1546         TVSCREENResetStartVideoTimer();
1547     else if ( c->contin_on ) {
1548 
1549         /*  Make sure cursor is back on when over video win  */
1550         if ( d->cursor_timer_set ) {
1551             XtRemoveTimeOut( d->cursor_timer );
1552             d->cursor_timer_set = FALSE;
1553         }
1554         d->cursor_dozeoff_enabled = FALSE;
1555         TVSCREENSetVideoWinCursorEnabled( TRUE );
1556 
1557         TVANNOTSetAutoUpdateMode( &d->annot, FALSE );
1558 
1559         TVCAPTUREStop( c );
1560 
1561         if ( !suppress_redraw && (c->xfer_mode == TV_TRANSFER_DIRECT )) {
1562 
1563             /*  Refresh where we were...  */
1564             TVSCREENUpdateRootRegion( d->refresh_geom, TVAPPCTX );
1565 
1566             /*  and where we are now (since the widgets on our video shell   */
1567             /*    can be stomped if, during a move, the user moved them      */
1568             /*    the video stream; the server then typically just BITBLTs   */
1569             /*    this trash around during the move, so we force a redraw)   */
1570             /*    when it sees fit to finally tell us about the Configure.   */
1571             shell_win = XtWindow( d->shell_wgt );
1572 
1573             TVSCREENGetWinGeometry( shell_win, &new_refresh_geom );
1574             TVSCREENWinGeometryToRoot( shell_win, new_refresh_geom,
1575                                        &new_refresh_geom );
1576 
1577             new_refresh_geom.x -=   REFRESH_SLACK_PIXELS;
1578             new_refresh_geom.y -=   REFRESH_SLACK_PIXELS;
1579             new_refresh_geom.w += 2*REFRESH_SLACK_PIXELS;
1580             new_refresh_geom.h += 2*REFRESH_SLACK_PIXELS;
1581             TVSCREENUpdateRootRegion( new_refresh_geom, TVAPPCTX );
1582         }
1583     }
1584     else {
1585         fprintf( stderr, "TVSCREENStopVideo called with no capture "
1586                          "pending or active...ignored\n" );
1587     }
1588 }
1589 
1590 /**@BEGINFUNC**************************************************************
1591 
1592     Prototype  : void TVSCREENVideoWinEventHdlr(
1593                       Widget     wgt,
1594                       XtPointer  cl_data,
1595                       XEvent    *ev,
1596                       Boolean   *continue_dispatch )
1597 
1598     Purpose    : Event handler for our video window's widget.
1599 
1600     Programmer : 04-Mar-97  Randall Hopper
1601 
1602     Parameters : wgt               - I: video window's widget
1603                  cl_data           - I: <not used>
1604                  ev                - I: xevent received for widget window
1605                  continue_dispatch - I: <not used>
1606 
1607     Returns    : None.
1608 
1609     Globals    : None.
1610 
1611  **@ENDFUNC*****************************************************************/
1612 
TVSCREENVideoWinEventHdlr(Widget wgt,XtPointer cl_data,XEvent * ev,Boolean * continue_dispatch)1613 void TVSCREENVideoWinEventHdlr(
1614          Widget     wgt,
1615          XtPointer  cl_data,
1616          XEvent    *ev,
1617          Boolean   *continue_dispatch )
1618 {
1619     static TV_INT32       S_call_level = 0;
1620 
1621     TV_DISPLAY        *d = &G_glob.display;
1622     TV_CAPTURE        *c = &G_glob.capture;
1623     TV_XSCREEN        *x = &G_glob.x;
1624     TV_AUDIO          *a = &G_glob.audio;
1625     char              *cfg_fail_msg;
1626     TV_BOOL            dirvid_allowed;
1627 
1628     if (( ev->type < 0 ) && ( ev->type >= XtNumber( event_names ) )) {
1629         fprintf( stderr, "VideoWin EVENT: Unknown %d!\n", ev->type );
1630         exit(1);
1631     }
1632 
1633     S_call_level++;
1634     EVPRINTF(( "%2ld: VideoWin EVENT: %s\n", S_call_level,
1635                                          event_names[ ev->type ] ));
1636 
1637     /*  Always keep recorded visibility state current  */
1638     if ( ev->type == VisibilityNotify )
1639         d->win_visibility = ev->xvisibility.state;
1640 
1641     /*  We don't do anything until the window's mapped, and even then,  */
1642     /*    not until the first Expose                                    */
1643     if ( d->win == None ) {
1644         if ( ev->type != Expose )
1645             goto RETURN;
1646         d->win = XtWindow( wgt );
1647 
1648         /*  When window is mapped, kick off enabled auto-behaviors  */
1649         if ( !d->enabled )
1650             goto RETURN;
1651 
1652         TVSCREENUpdateWinGeometry();
1653         TVSCREENSetVideoWinGeom( d->geom );           /*  Tweak if necessary */
1654 
1655         /*  Kick off a single- or continuous-capture  */
1656         if ( RES_MULT_OK(d,c) ) {
1657 
1658             if ( !TVSCREENCapConfigure( d->cap_mode, &cfg_fail_msg ) ) {
1659                 fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n",
1660                                  cfg_fail_msg );
1661                 goto RETURN;
1662             }
1663 
1664             /*  Ready to roll; unmute audio now  */
1665             TVCAPTURESetAudioMute( c, a->mute_on );
1666 
1667             TVSCREENStartVideo();
1668         }
1669         else
1670             d->waiting_for_resize = TRUE;
1671         goto RETURN;
1672     }
1673 
1674     dirvid_allowed = !App_res.disable_direct_v &&
1675                   ( x->visual_modes[ x->active_visual ] & TV_TRANSFER_DIRECT );
1676 
1677     switch ( ev->type ) {
1678 
1679         case VisibilityNotify:
1680 
1681             EVPRINTF(( "\t\t%s\n",visibility_names[ ev->xvisibility.state ]));
1682 
1683             /*  No need to process when we're frozen or otherwise disabled  */
1684             if ( d->freeze_on || !d->enabled )
1685                 break;
1686 
1687             /*  If now fully obscured, stop capture & force a redraw  */
1688             if ( ev->xvisibility.state == VisibilityFullyObscured ) {
1689                 if ( TVSCREENVideoStarted() )
1690                     TVSCREENStopVideo( False );
1691             }
1692 
1693             /*  Else we are now partially or totally visible.                */
1694             /*    If we aren't capturing, start.                             */
1695             /*    If we already are (e.g. partial<->total), we only need     */
1696             /*    to stop and restart if direct video is an option.          */
1697             /*  We use direct video when unobscured for max frame rate       */
1698             /*    and min system load, and switch to ximages when partially  */
1699             /*    obscured to let the X Server do clipping for us.           */
1700             else {
1701                 TV_BOOL contin_on = TVSCREENVideoStarted() &&
1702                                     TVSCREENVideoReqCaptureContin();
1703 
1704                 if (( !contin_on || dirvid_allowed ) && RES_MULT_OK(d,c) ) {
1705                     if ( TVSCREENVideoStarted() )
1706                         TVSCREENStopVideo( False );
1707 
1708                     if ( !TVSCREENCapConfigure( d->cap_mode, &cfg_fail_msg ) ){
1709                         fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n",
1710                                          cfg_fail_msg );
1711                         break;
1712                     }
1713                     TVSCREENStartVideo();
1714                 }
1715             }
1716             break;
1717 
1718         case ConfigureNotify:
1719 
1720             /*  First, stop any running capture && force a redraw  */
1721             if ( d->enabled &&
1722                  TVSCREENVideoStarted() && TVSCREENVideoReqCaptureContin() ) {
1723                 TVSCREENStopVideo( False );
1724                 TVSCREENStartVideo();
1725             }
1726 
1727             /*  Always keep window geom up-to-date  */
1728             TVSCREENUpdateWinGeometry();
1729 
1730             /*  Tweak geometry if necessary  */
1731             TVSCREENSetVideoWinGeom( d->geom );
1732             break;
1733 
1734         case Expose :
1735 
1736             /*  Ignore all but the last expose  */
1737             if ( ev->xexpose.count != 0 )
1738                 break;
1739 
1740             /*  If capture is stopped and saved ximage looks reasonable,  */
1741             /*    blast it back up there.                                 */
1742             TVSCREENRedrawVideoWin();
1743             break;
1744 
1745         case MotionNotify :
1746 
1747             /*  Wake up the cursor, if its sleeping  */
1748             TVSCREENWakeupCursor();
1749             break;
1750     }
1751 
1752  RETURN:
1753     S_call_level--;
1754     return;
1755 }
1756 
1757 
1758 /**@BEGINFUNC**************************************************************
1759 
1760     Prototype  : void TVSCREENShellWinEventHdlr(
1761                       Widget     wgt,
1762                       XtPointer  cl_data,
1763                       XEvent    *ev,
1764                       Boolean   *continue_dispatch )
1765 
1766     Purpose    : Event handler for our shell window's widget.
1767 
1768     Programmer : 04-Mar-97  Randall Hopper
1769 
1770     Parameters : wgt               - I: shell window's widget
1771                  cl_data           - I: <not used>
1772                  ev                - I: xevent received for widget window
1773                  continue_dispatch - I: <not used>
1774 
1775     Returns    : None.
1776 
1777     Globals    : None.
1778 
1779  **@ENDFUNC*****************************************************************/
1780 
TVSCREENShellWinEventHdlr(Widget wgt,XtPointer cl_data,XEvent * ev,Boolean * continue_dispatch)1781 void TVSCREENShellWinEventHdlr(
1782          Widget     wgt,
1783          XtPointer  cl_data,
1784          XEvent    *ev,
1785          Boolean   *continue_dispatch )
1786 {
1787     TV_DISPLAY        *d = &G_glob.display;
1788     TV_CAPTURE        *c = &G_glob.capture;
1789     TV_AUDIO          *a = &G_glob.audio;
1790     char              *cfg_fail_msg;
1791 
1792     if (( ev->type < 0 ) && ( ev->type >= XtNumber( event_names ) ))
1793         EVPRINTF(( "--- ShellWin EVENT: Unknown %d!\n", ev->type ));
1794     else
1795         EVPRINTF(( "--- ShellWin EVENT: %s\n", event_names[ ev->type ] ));
1796 
1797     /*  We don't do anything until our video window's mapped  */
1798     if ( d->win == None )
1799         goto RETURN;
1800 
1801     switch ( ev->type ) {
1802         case UnmapNotify:
1803             /*  When we unmap (e.g. shell iconified), stop capture  */
1804             if ( d->enabled && TVSCREENVideoStarted() )
1805                 TVSCREENStopVideo( False );
1806             break;
1807 
1808         case ConfigureNotify:
1809 
1810             /*  FIXME:  Really all we need to do here is catch the        */
1811             /*    cases where the shell (and all children including our   */
1812             /*    video window) have moved because a Configure "won't" be */
1813             /*    sent to our video window for this.  But for now, this   */
1814             /*    will stop/config/start the video twice on a shell       */
1815             /*    resize; once for this config and once for the video     */
1816             /*    win config.                                             */
1817 
1818             /*  First, stop any running capture && force a redraw  */
1819             if ( d->enabled &&
1820                  TVSCREENVideoStarted() && TVSCREENVideoReqCaptureContin() ) {
1821                 TVSCREENStopVideo( False );
1822                 TVSCREENStartVideo();
1823             }
1824 
1825             /*  Always keep window geom up-to-date  */
1826             TVSCREENUpdateWinGeometry();
1827 
1828             /*  Tweak geometry if necessary  */
1829             TVSCREENSetVideoWinGeom( d->geom );
1830 
1831             /*  If we've just mapped and were waiting for resize, start  */
1832             if ( d->waiting_for_resize && RES_MULT_OK(d,c) ) {
1833                 d->waiting_for_resize = FALSE;
1834 
1835                 if ( !TVSCREENCapConfigure( d->cap_mode, &cfg_fail_msg ) ) {
1836                     fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n",
1837                                      cfg_fail_msg );
1838                     goto RETURN;
1839                 }
1840 
1841                 /*  Ready to roll; unmute audio now  */
1842                 TVCAPTURESetAudioMute( c, a->mute_on );
1843 
1844                 if ( TVSCREENVideoStarted() )
1845                     TVSCREENStopVideo( False );
1846                 TVSCREENStartVideo();
1847             }
1848 
1849             break;
1850 
1851         case EnterNotify:
1852 
1853             /*  Resync menu options and tools with driver defaults  */
1854             TVMENUResync();
1855             TVTOOLSResync();
1856             TVAPPEARDIALOGResync();
1857             break;
1858 
1859     }
1860 
1861  RETURN:
1862     return;
1863 }
1864 
1865 
1866 /**@BEGINFUNC**************************************************************
1867 
1868     Prototype  : void TVSCREENSetVideoWinGeom(
1869                       TV_GEOM videowin_geom )
1870 
1871     Purpose    : Resize the application such that the video window is
1872                  the specified size
1873 
1874                  Note that the width will be adjusted to be a multiple of
1875                  2 so we don't have to fool with scan line padding when doing
1876                  ximage conversion/display.
1877 
1878     Programmer : 08-Mar-97  Randall Hopper
1879 
1880     Parameters : videowin_geom - I: desired geometry for video subwindow
1881 
1882     Returns    : None.
1883 
1884     Globals    : None.
1885 
1886  **@ENDFUNC*****************************************************************/
1887 
TVSCREENSetVideoWinGeom(TV_GEOM videowin_geom)1888 void TVSCREENSetVideoWinGeom(
1889          TV_GEOM videowin_geom )
1890 {
1891     TV_DISPLAY        *d = &G_glob.display;
1892     TV_CAPTURE        *c = &G_glob.capture;
1893     TV_GEOM            g = videowin_geom;
1894     int                shell_x,
1895                        shell_y;
1896     Window             child_win;
1897     TV_INT32           w,
1898                        h;
1899 
1900     /*  And if aspect lock is on, tweak back to 4:3 ratio  */
1901     if ( d->aspect_lock ) {
1902         h   = ( g.h + g.w * 3 / 4 ) / 2;
1903         w   = h * 4 / 3;
1904 
1905         /*  Don't sweat the round-off errors  */
1906         if (( abs(g.h - h) > 1 ) || ( abs(g.w - w) > 1 ))
1907             g.w = w, g.h = h;
1908     }
1909 
1910     /*  Update based on capture res limits  */
1911     g.w = g.w / c->width_res  * c->width_res;
1912     g.h = g.h / c->height_res * c->height_res;
1913 
1914     /*  If we're already there, no need to do anything  */
1915     if ( memcmp( &d->geom, &g, sizeof( g )) == 0 )
1916         return;
1917 
1918     assert( XtIsRealized( d->shell_wgt ) );
1919     assert( XtIsRealized( d->video_wgt ) );
1920 
1921     /*  Propagete new size to annotations  */
1922     TVANNOTSetDrawable( &d->annot, XtWindow( d->video_wgt ) );
1923     TVANNOTSetDrawableSize( &d->annot, g.w, g.h );
1924 
1925     /*  Recompute new shell coordinates that'll put our video window  */
1926     /*    where we want it.                                           */
1927     if ( !XTranslateCoordinates( TVDISPLAY,
1928                                  XtWindow( d->video_wgt ),
1929                                  XtWindow( d->shell_wgt ),
1930                                  0, 0,
1931                                  &shell_x, &shell_y, &child_win ) ) {
1932         fprintf( stderr, "XTranslateCoordinates() failed\n" );
1933         exit(1);
1934     }
1935     g.x -= shell_x;
1936     g.y -= shell_y;
1937 
1938 #ifdef BUSTED
1939     /*  I'm doin' somethin wrong  */
1940     /*  Doesn't work and freeezes the prog for a few seconds  */
1941     XtVaSetValues( d->shell_wgt, XtNx, g.x,
1942                                  XtNy, g.y,
1943                                  NULL );
1944 #endif
1945     EVPRINTF(( "Resetting video widget geometry: %ldx%ld\n", g.w, g.h ));
1946 #ifdef OLD
1947     XawPanedSetRefigureMode( XtParent( d->video_wgt ), False );
1948     XtVaSetValues( d->video_wgt, XtNwidth , g.w,
1949                                  XtNheight, g.h,
1950                                  NULL );
1951     XawPanedSetRefigureMode( XtParent( d->video_wgt ), True );
1952 #endif
1953     g.w += shell_x;
1954     g.h += shell_y;
1955     XtVaSetValues( d->shell_wgt, XtNx        , g.x,
1956                                  XtNy        , g.y,
1957                                  XtNwidth    , g.w,
1958                                  XtNheight   , g.h,
1959                                  XtNmaxWidth , shell_x + c->width_max,
1960                                  XtNmaxHeight, shell_y + c->height_max,
1961                                  NULL );
1962 }
1963 
1964 
1965 /**@BEGINFUNC**************************************************************
1966 
1967     Prototype  : void TVSCREENGetVideoWinGeom(
1968                       TV_GEOM *videowin_geom )
1969 
1970     Purpose    : Return the most recently registered position of the video
1971                  window.
1972 
1973                  It is an error to call this before the video window is
1974                  mapped (because the geometry doesn't exist).
1975 
1976     Programmer : 06-Oct-97  Randall Hopper
1977 
1978     Parameters : videowin_geom - O: most recently queried geometry
1979 
1980     Returns    : None.
1981 
1982     Globals    : None.
1983 
1984  **@ENDFUNC*****************************************************************/
1985 
TVSCREENGetVideoWinGeom(TV_GEOM * videowin_geom)1986 void TVSCREENGetVideoWinGeom(
1987          TV_GEOM *videowin_geom )
1988 {
1989     TV_DISPLAY        *d = &G_glob.display;
1990 
1991     if ( d->win == None ) {
1992         fprintf( stderr, "TVSCREENGetVideoWinGeom called before video "
1993                          "window mapped\n" );
1994         exit(1);
1995     }
1996 
1997     memcpy( videowin_geom, &d->geom, sizeof( *videowin_geom ) );
1998 }
1999 
2000 
2001 /**@BEGINFUNC**************************************************************
2002 
2003     Prototype  : void TVSCREENUpdateShellRsrcs(
2004                       Widget shell_wgt,
2005                       Widget video_wgt )
2006 
2007     Purpose    : Update the max width/height of our shell based on
2008                  max width/height of video window imposed by
2009                  capture size limitations.
2010 
2011     Programmer : 08-Mar-97  Randall Hopper
2012 
2013     Parameters : shell_wgt - I: shell widget
2014                  video_wgt - I: video widget
2015 
2016     Returns    : None.
2017 
2018     Globals    : None.
2019 
2020  **@ENDFUNC*****************************************************************/
2021 
TVSCREENUpdateShellRsrcs(Widget shell_wgt,Widget video_wgt)2022 void TVSCREENUpdateShellRsrcs( Widget shell_wgt, Widget video_wgt )
2023 {
2024     TV_CAPTURE *c = &G_glob.capture;
2025     int         shell_x,
2026                 shell_y;
2027     Window      child_win;
2028 
2029     if ( !XTranslateCoordinates( TVDISPLAY,
2030                                  XtWindow( video_wgt ),
2031                                  XtWindow( shell_wgt ),
2032                                  0, 0,
2033                                  &shell_x, &shell_y, &child_win ) ) {
2034         fprintf( stderr, "XTranslateCoordinates() failed\n" );
2035         exit(1);
2036     }
2037     XtVaSetValues( shell_wgt, XtNmaxWidth , shell_x + c->width_max,
2038                               XtNmaxHeight, shell_y + c->height_max,
2039                               NULL );
2040 }
2041 
2042 
2043 /**@BEGINFUNC**************************************************************
2044 
2045     Prototype  : static void STVSCREENSwitchToMode(
2046                       TV_XSCREEN           *s,
2047                       int                   cur_vm,
2048                       int                   new_vm )
2049 
2050     Purpose    : Wrapper function used to hide the mess we have to go
2051                  through because XF86VidModeSwitchToMode doesn't work in
2052                  some versions of the VM extension.  For these versions,
2053                  we have to simulate it with multiple XF86VidModeSwitchMode
2054                  calls.
2055 
2056     Programmer : 24-May-97  Randall Hopper
2057 
2058     Parameters : s       - I: X screen def struct
2059                  cur_vm  - I: index of video mode we're currently in
2060                  new_vm  - I: index of video mode to switch to
2061 
2062     Returns    : None.
2063 
2064     Globals    : None.
2065 
2066  **@ENDFUNC*****************************************************************/
STVSCREENSwitchToMode(TV_XSCREEN * s,int cur_vm,int new_vm)2067 static void STVSCREENSwitchToMode( TV_XSCREEN           *s,
2068                                    int                   cur_vm,
2069                                    int                   new_vm )
2070 {
2071     if ( !s->vmode_ext_supported ) {
2072         fprintf( stderr,
2073                  "STVSCREENSwitchToMode called without VidMode ext support\n" );
2074         exit(1);
2075     }
2076 
2077 #ifdef HAVE_XFREE86
2078     /*  NOTE: XF86VidModeSwitchToMode dumps core on VMode <= 0.7        */
2079     /*    (XFree <= 3.2A) w/ S3 & S3V servers (ModeInfo private data    */
2080     /*    is garbage).  David Dawes @ XFree said he fixed this 5/24/97  */
2081     /*    and it'd be in 3.3 w/ VMode >= 0.8.  Not confirmed yet.       */
2082     if ( VERS_SAME_OR_NEWER( s->vmode_majv, s->vmode_minv, 0, 8 ) )
2083         XF86VidModeSwitchToMode( TVDISPLAY, TVSCREEN, (s->vm_list)[ new_vm ] );
2084     else {
2085 
2086         /*  NOTE - 6/15/98 - As of XFree86 3.3.1 (& .2 probably), there's    */
2087         /*    no way to know whether the vidmode extension is truly enabled. */
2088         /*    It's advertised even when -disableVidMode was specified or     */
2089         /*    if the client is remote and -allowNonLocalXvidtune was not     */
2090         /*    specified.  As a result, VidMode calls may spontaneously fail  */
2091         /*    with an XError.                                                */
2092         /*  For this reason, we just disable VidMode when running remotely   */
2093         /*    as its probably not enabled, but this can still bite us if     */
2094         /*    the user is running locally and has specified -disableVidMode. */
2095         /*    This is particulary nasty since we have a Mouse grab active    */
2096         /*    active at that point and XFree86 has another bug where it      */
2097         /*    doesn't release the mouse grab when the client dies.           */
2098         /*  FIXME: XFree86 will hopefull fix these two bugs: release DGA     */
2099         /*    mouse grab when client dies, and provide method to query       */
2100         /*    whether vidmode extension is really available.                 */
2101 
2102         int i,
2103             inc = (new_vm > cur_vm) ? 1 : -1;
2104 
2105         for ( i = cur_vm; i != new_vm; i += inc )  {
2106             if ( !XF86VidModeSwitchMode( TVDISPLAY, TVSCREEN,
2107                                          (inc > 0) ? 1 : 0 ) ) {
2108                 fprintf( stderr,
2109                          "XF86VidModeSwitchMode() failed\n" );
2110                 exit(1);
2111             }
2112         }
2113     }
2114 #endif
2115 }
2116 
2117 /**@BEGINFUNC**************************************************************
2118 
2119     Prototype  : void TVSCREENSetZoomState(
2120                       TV_BOOL zoom_on,
2121                       TV_BOOL full_screen )
2122 
2123     Purpose    : Toggles Zoom (max capture res) mode on and off.
2124 
2125                  If full_screen is on when zooming, the video mode and
2126                  viewport origin will be adjusted to make the video window
2127                  fill as much of the monitor display area as possible.
2128 
2129     Programmer : 05-Mar-97  Randall Hopper
2130 
2131     Parameters : zoom_on     - I: T = zoom; F = unzoom
2132                  full_screen - I: if zoom_on = TRUE, chg vid mode and
2133                                   adjust viewport so video win fills monitor
2134 
2135     Returns    : None.
2136 
2137     Globals    : None.
2138 
2139  **@ENDFUNC*****************************************************************/
2140 
TVSCREENSetZoomState(TV_BOOL zoom_on,TV_BOOL full_screen)2141 void TVSCREENSetZoomState(
2142          TV_BOOL zoom_on,
2143          TV_BOOL full_screen )
2144 {
2145     TV_DISPLAY        *d = &G_glob.display;
2146     TV_XSCREEN        *s = &G_glob.x;
2147     TV_CAPTURE        *c = &G_glob.capture;
2148     TV_GEOM            g,
2149                        vp;
2150     int                cur_vm = -1,
2151                        new_vm = -1;
2152     TV_BOOL            need_video_restart,
2153                        vport_api_works = FALSE;
2154     Dimension          vm_width,
2155                        vm_height,
2156                        dpy_width = DisplayWidth(TVDISPLAY,TVSCREEN),
2157                        dpy_height= DisplayHeight(TVDISPLAY,TVSCREEN);
2158 
2159     if ( zoom_on == d->zoom_on )
2160         return;
2161 
2162     if ( s->vmode_ext_supported ) {
2163         cur_vm = TVSCREENGetCurVidMode( s );
2164 
2165 #ifdef HAVE_XFREE86
2166         vport_api_works = VERS_SAME_OR_NEWER( s->vmode_majv, s->vmode_minv,
2167                                               0, 8 );
2168 #endif
2169     }
2170 
2171     /*  First, stop any running capture && force a redraw.             */
2172     /*    We don't want to be DMAing to the video card when its being  */
2173     /*    reconfigured for a new mode or it can hang the system.       */
2174     need_video_restart = FALSE;
2175 
2176     if ( d->enabled && TVSCREENVideoStarted() &&
2177          TVSCREENVideoReqCaptureContin() && s->vmode_ext_supported &&
2178          ((  zoom_on && full_screen ) ||
2179           ( !zoom_on && (cur_vm != d->unzoomed.mode) )) ) {
2180 
2181         TVSCREENStopVideo( False );
2182         XSync( TVDISPLAY, False );
2183         need_video_restart = TRUE;
2184     }
2185 
2186     /*  When we go into zoom mode, try to keep the same upper-left, but  */
2187     /*    adjust it if we need to in order to stay on the display.       */
2188     /*  When zooming to full-screen, change the video mode and viewport  */
2189     /*    so that the video window fills as much of the screen as        */
2190     /*    possible.                                                      */
2191     /*  FIXME:  full-screen viewport behavior not as described due to    */
2192     /*    XFree 3.2A bugs in video mode extension.  For now, on          */
2193     /*    full-screen zoom, put video win in upper-left of desktop and   */
2194     /*    just change modes.                                             */
2195     /*  When we go back to unzoomed, go back to exactly where we were    */
2196     /*    and what size we were.                                         */
2197     /*  XFREE BUG:  Note that if you attempt to set the desktop viewport */
2198     /*    origin (even if to 0,0) when the desktop (display) size ==     */
2199     /*    the video mode resolution, X throws you off into unused video  */
2200     /*    memory somewhere.  So avoid this bug and don't call it then    */
2201     /*    (we really don't need to anyway).                              */
2202 
2203     if ( zoom_on ) {
2204         d->unzoomed.geom = d->geom;         /*  Save old  */
2205         if ( !s->vmode_ext_supported || !full_screen ) {
2206             d->unzoomed.mode    =
2207             d->unzoomed.viewp_x =
2208             d->unzoomed.viewp_y = -1;
2209         }
2210 #ifdef HAVE_XFREE86
2211         else {
2212             d->unzoomed.mode = s->vm_startup;
2213             if ( vport_api_works )
2214                 XF86VidModeGetViewPort( TVDISPLAY, TVSCREEN,
2215                                   &d->unzoomed.viewp_x, &d->unzoomed.viewp_y );
2216         }
2217 #endif
2218 
2219         g   = d->geom;
2220         g.w = c->width_max;
2221         g.h = c->height_max;
2222 
2223         if ( !vport_api_works && full_screen )
2224             g.x = g.y = 0;
2225         else {
2226             if ( g.x + g.w - 1 >= dpy_width )
2227                 g.x -= (g.x+g.w) - dpy_width;
2228             if ( g.y + g.h - 1 >= dpy_height )
2229                 g.y -= (g.y+g.h) - dpy_height;
2230 
2231             if ( g.x < 0 )
2232                 g.x = 0, g.w = dpy_width;
2233             if ( g.y < 0 )
2234                 g.y = 0, g.h = dpy_height;
2235         }
2236     }
2237     else {
2238         g = d->unzoomed.geom;
2239     }
2240 
2241     /*  Do it  */
2242     TVSCREENSetVideoWinGeom( g );
2243 
2244     /*  If full-screen was requested, determine whether it makes sense  */
2245     /*    based on whether we're going to change modes.                 */
2246     if ( zoom_on && full_screen ) {
2247         new_vm = TVSCREENClosestVidMode( s, g.w, g.h );
2248         if (( new_vm < 0 ) || ( cur_vm == new_vm )) {
2249             full_screen = FALSE;
2250             d->unzoomed.mode = -1;
2251         }
2252     }
2253 
2254     /*  Deal with full-screen mode changes on zoom/unzoom.                 */
2255     /*    Also change viewport origins to coincide with zoomed video win.  */
2256 #ifdef HAVE_XFREE86
2257     if ( s->vmode_ext_supported ) {
2258         assert( cur_vm >= 0 );
2259 
2260         if ( zoom_on ) {
2261             if ( full_screen ) {
2262                 XRaiseWindow( TVDISPLAY, XtWindow(d->shell_wgt) );
2263 
2264                 /*  Lock out the mouse so user can't move off the TV.       */
2265                 if ( s->dga_ext_supported )
2266                     XF86DGADirectVideo( TVDISPLAY, TVSCREEN,
2267                                         XF86DGADirectMouse );
2268 
2269                 if ( new_vm >= 0 ) {
2270                     vp.x = g.x, vp.y = g.y;
2271 
2272                     STVSCREENSwitchToMode( s, cur_vm, new_vm );
2273 
2274                     TVSCREENGetVidModeGeometry( s, new_vm,
2275                                                 &vm_width, &vm_height);
2276 
2277                     if ( vp.x + vm_width > dpy_width )
2278                       vp.x = dpy_width - vm_width;
2279                     if ( vp.y + vm_height > dpy_height )
2280                       vp.y = dpy_height - vm_height;
2281 
2282                     if ( vport_api_works && ( vp.x >= 0 ) && ( vp.y >= 0 ) )
2283                         XF86VidModeSetViewPort( TVDISPLAY, TVSCREEN,
2284                                                 vp.x, vp.y);
2285                     XSync( TVDISPLAY, False );
2286                 }
2287 
2288                 /*  Warp the pointer to the middle of the window.  */
2289                 if ( s->dga_ext_supported )
2290                     XWarpPointer( TVDISPLAY, None,
2291                                   RootWindow( TVDISPLAY, TVSCREEN ),
2292                                   0,0,0,0, g.x+g.w/2, g.y+g.h/2 );
2293             }
2294         }
2295         else {
2296             if ( d->unzoomed.mode >= 0 ) {
2297                 if ( cur_vm != d->unzoomed.mode ) {
2298                     new_vm = d->unzoomed.mode;
2299                     STVSCREENSwitchToMode( s, cur_vm, new_vm );
2300                 }
2301                 if ( vport_api_works & ( d->unzoomed.viewp_x >= 0 ) )
2302                     XF86VidModeSetViewPort( TVDISPLAY, TVSCREEN,
2303                                             d->unzoomed.viewp_x,
2304                                             d->unzoomed.viewp_y );
2305                 if ( s->dga_ext_supported )
2306                     XF86DGADirectVideo( TVDISPLAY, TVSCREEN, 0 );
2307                 XSync( TVDISPLAY, False );
2308             }
2309         }
2310     }
2311 #endif
2312 
2313     d->zoom_on = !d->zoom_on;
2314 
2315     /*  Give annotation a chance to resync annot size for new mode  */
2316     TVANNOTSetDrawable( &d->annot, XtWindow( d->video_wgt ) );
2317     TVANNOTSetDrawableSize( &d->annot, g.w, g.h );
2318 
2319     /*  Finally, restart video if it was running before  */
2320     if ( need_video_restart )
2321         TVSCREENStartVideo();
2322 }
2323 
2324 
2325 /**@BEGINFUNC**************************************************************
2326 
2327     Prototype  : void TVSCREENSetFreezeState(
2328                       TV_BOOL freeze_on )
2329 
2330     Purpose    : Toggle on and off frozen display.
2331 
2332     Programmer : 08-Mar-97  Randall Hopper
2333 
2334     Parameters : freeze_on - I: T = freeze; F = continuous update
2335 
2336     Returns    : None.
2337 
2338     Globals    : None.
2339 
2340  **@ENDFUNC*****************************************************************/
2341 
TVSCREENSetFreezeState(TV_BOOL freeze_on)2342 void TVSCREENSetFreezeState(
2343          TV_BOOL freeze_on )
2344 {
2345     TV_DISPLAY        *d = &G_glob.display;
2346     char              *cfg_fail_msg;
2347 
2348     if ( !d->enabled )
2349         return;
2350 
2351     if ( freeze_on && TVSCREENVideoStarted() ) {
2352 
2353         /*  Stop continuous and capture a single intact frame   */
2354         /*    to memory to display persistently in the window.  */
2355         TVSCREENStopVideo( True );
2356 
2357         if ( !TVSCREENCapConfigure( TV_CAPTURE_SINGLE, &cfg_fail_msg ) ) {
2358             fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n",
2359                              cfg_fail_msg );
2360             return;
2361         }
2362         TVSCREENStartVideo();
2363         d->cap_mode  = TV_CAPTURE_SINGLE;
2364         d->freeze_on = TRUE;
2365     }
2366     else if ( !freeze_on &&
2367               !( TVSCREENVideoStarted() && TVSCREENVideoReqCaptureContin() ) ){
2368 
2369         /*  Start continuous  */
2370         if ( !TVSCREENCapConfigure( TV_CAPTURE_CONTINUOUS, &cfg_fail_msg ) ) {
2371             fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n",
2372                              cfg_fail_msg );
2373             return;
2374         }
2375         TVSCREENStartVideo();
2376         d->cap_mode = TV_CAPTURE_CONTINUOUS;
2377         d->freeze_on = FALSE;
2378     }
2379 }
2380 
TVSCREENToggleFreezeState(void)2381 void TVSCREENToggleFreezeState( void )
2382 {
2383     TV_DISPLAY        *d = &G_glob.display;
2384 
2385     TVSCREENSetFreezeState( !d->freeze_on );
2386 }
2387 
2388 
TVSCREENSetScreenUpdateEnabled(TV_BOOL enabled)2389 void TVSCREENSetScreenUpdateEnabled(
2390          TV_BOOL enabled )
2391 {
2392     TV_DISPLAY        *d = &G_glob.display;
2393     char              *cfg_fail_msg;
2394 
2395     if ( enabled == d->enabled ) {
2396         fprintf( stderr, "TVSCREENSetScreenUpdateEnabled: new/was=%ld\n",
2397                  enabled );
2398         return;
2399     }
2400 
2401     if ( d->enabled ) {
2402         d->enabled = False;
2403         if ( TVSCREENVideoStarted() )
2404             TVSCREENStopVideo( True );
2405     }
2406     else {
2407         d->enabled = True;
2408         TVCAPTUREClearPendingFrames();
2409 
2410         if ( d->freeze_on ) {
2411 
2412             /*  Capture a single intact frame to memory to display  */
2413             /*    persistently in the window.                       */
2414             if ( !TVSCREENCapConfigure( TV_CAPTURE_SINGLE, &cfg_fail_msg ) ) {
2415                 fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n",
2416                                  cfg_fail_msg );
2417                 return;
2418             }
2419             TVSCREENStartVideo();
2420             d->cap_mode  = TV_CAPTURE_SINGLE;
2421         }
2422         else {
2423 
2424             /*  Start continuous  */
2425             if ( !TVSCREENCapConfigure( TV_CAPTURE_CONTINUOUS, &cfg_fail_msg)){
2426                 fprintf( stderr, "TVSCREENCapConfigure() failed: %s\n",
2427                                  cfg_fail_msg );
2428                 return;
2429             }
2430             TVSCREENStartVideo();
2431             d->cap_mode = TV_CAPTURE_CONTINUOUS;
2432         }
2433     }
2434 }
2435 
2436 
2437 
2438 /**@BEGINFUNC**************************************************************
2439 
2440     Prototype  : static void TVSCREENPrepXImage(
2441                       TV_DISPLAY  *d,
2442                       TV_GEOM     *g,
2443                       XVisualInfo *v )
2444 
2445     Purpose    : Verifies that the XImage currently allocated to move
2446                  captured images into satisfies the requirements for the
2447                  resolution and depth we're going to be stuffing into it.
2448 
2449                  If not, the XImage is reallocated.
2450 
2451                  Also, if pixel conversion or quantization is going to be
2452                  necessary to display the image, verifies that the
2453                  appropriate conversion array is populated.
2454 
2455     Programmer : 07-Mar-97  Randall Hopper
2456 
2457     Parameters : d - I: display struct
2458                  g - I: desired image geometry
2459                  v - I: visual to use
2460 
2461     Returns    : None.
2462 
2463     Globals    : None.
2464 
2465  **@ENDFUNC*****************************************************************/
2466 
TVSCREENPrepXImage(TV_DISPLAY * d,TV_GEOM * g,XVisualInfo * v)2467 static void TVSCREENPrepXImage( TV_DISPLAY  *d,
2468                                 TV_GEOM     *g,
2469                                 XVisualInfo *v )
2470 {
2471     TV_CAPTURE *c = &G_glob.capture;
2472     TV_XIMAGE  *image = &d->ximage;
2473 
2474     /**************************************/
2475     /*  Create a new image if we need to  */
2476     /**************************************/
2477     if ( ! (( image->ximg             != NULL        ) &&
2478             ( image->visual->visualid == v->visualid ) &&
2479             ( image->geom.w           == g->w        ) &&
2480             ( image->geom.h           == g->h        ))) {
2481 
2482         d->ximage_use_for_expose = FALSE;
2483 
2484         /*  Free the old  */
2485         if ( image->ximg )
2486             if ( image->is_shm ) {
2487                 if ( !XShmDetach   ( TVDISPLAY, &image->shm_info ) ) {
2488                     fprintf( stderr, "XShmDetach() failed\n" );
2489                     exit(1);
2490                 }
2491                 XDestroyImage( image->ximg );
2492                 image->ximg = NULL;
2493                 if ( shmdt ( image->shm_info.shmaddr ) ) {
2494                     fprintf( stderr, "shmdt() failed: %s\n", strerror(errno));
2495                     exit(1);
2496                 }
2497                 if ( shmctl( image->shm_info.shmid, IPC_RMID, 0 ) ) {
2498                     fprintf( stderr, "shmctl() failed: %s\n",strerror(errno));
2499                     exit(1);
2500                 }
2501                 image->is_shm = False;
2502             }
2503             else {
2504                 free( image->ximg->data );
2505                 image->ximg->data = NULL;
2506                 XDestroyImage( image->ximg );
2507                 image->ximg = NULL;
2508             }
2509 
2510         /*  Create desired new  */
2511         if ( c->xfer_mode == TV_TRANSFER_SHMEM_IMAGE ) {
2512             /*  FIXME:  Clean up shared mem segments on exit and on  */
2513             /*          next run.                                    */
2514             image->ximg = XShmCreateImage( TVDISPLAY, v->visual, v->depth,
2515                                            ZPixmap, NULL, &image->shm_info,
2516                                            g->w, g->h );
2517             if ( image->ximg == NULL ) {
2518                 fprintf( stderr, "XShmCreateImage() failed\n" );
2519                 exit(1);
2520             }
2521             image->shm_info.shmid = shmget( IPC_PRIVATE,
2522                            image->ximg->bytes_per_line * image->ximg->height,
2523                            IPC_CREAT | 0777 );
2524             if ( image->shm_info.shmid < 0 ) {
2525                 fprintf( stderr, "shmget() failed: %s\n", strerror(errno));
2526                 exit(1);
2527             }
2528             image->shm_info.shmaddr  =
2529             image->ximg->data        = shmat( image->shm_info.shmid, 0, 0 );
2530             if ( image->ximg->data == NULL ) {
2531                 fprintf( stderr, "shmat() failed: %s\n", strerror(errno));
2532                 exit(1);
2533             }
2534             image->shm_info.readOnly = True;
2535             if ( !XShmAttach( TVDISPLAY, &image->shm_info ) ) {
2536                 fprintf( stderr, "XShmAttach() failed\n" );
2537                 exit(1);
2538             }
2539             image->is_shm = True;
2540 
2541             /*printf( "ImageByteOrder = %s\n",
2542                     image->ximg->byte_order == LSBFirst ? "LSB" : "MSB" );*/
2543         }
2544         else if ( c->xfer_mode == TV_TRANSFER_STD_IMAGE ) {
2545             image->ximg = XCreateImage( TVDISPLAY, v->visual, v->depth,
2546                                         ZPixmap, 0, NULL, g->w, g->h,
2547                                         BitmapPad(TVDISPLAY), 0 );
2548             if ( image->ximg == NULL ) {
2549                 fprintf( stderr, "XCreateImage() failed\n" );
2550                 exit(1);
2551             }
2552             image->ximg->data = malloc( image->ximg->bytes_per_line *
2553                                         image->ximg->height );
2554             if ( image->ximg->data == NULL )
2555                 TVUTILOutOfMemory();
2556             image->is_shm = False;
2557         }
2558         else {
2559             fprintf( stderr, "TVSCREENPrepXImage() - Unsupported "
2560                              "xfer_mode %d\n", c->xfer_mode );
2561             exit(1);
2562         }
2563         image->geom   = *g;
2564         image->visual = v;
2565     }
2566 }
2567 
2568 
2569 /**@BEGINFUNC**************************************************************
2570 
2571     Prototype  : static void TVSCREENAllocColorCube(
2572                       TV_DISPLAY   *d,
2573                       VL_COLORMAP **cmap )
2574 
2575     Purpose    : Creates the largest colorcube that the default 8-bit
2576                  colormap will allow.  This is used to map direct color
2577                  images for pseudocolor display.
2578 
2579     Programmer : 08-Mar-97  Randall Hopper
2580 
2581     Parameters : d    - I: display struct
2582                  cmap - O: allocated colormap struct, with allocated colors
2583 
2584     Returns    : None.
2585 
2586     Globals    : None.
2587 
2588  **@ENDFUNC*****************************************************************/
2589 
TVSCREENAllocColorCube(TV_DISPLAY * d,VL_COLORMAP ** cmap)2590 static void TVSCREENAllocColorCube( TV_DISPLAY   *d,
2591                                     VL_COLORMAP **cmap )
2592 {
2593     static Color_cubes[][3] =
2594       { {7,7,5},{6,6,6},{6,6,5},{6,6,4},{5,5,5},{5,5,4},{5,5,3},
2595         {4,4,4},{3,3,3},{2,2,2} };
2596 
2597 #define MAX_CUBE_DIM 7
2598 #define MIN_BRIGHT   0.0
2599 #define MAX_BRIGHT   1.0
2600 
2601     XColor   col[ 256 ];
2602     TV_INT32 i,
2603              r,g,b,
2604              num_col,
2605              cube_idx,
2606              r_dim, g_dim, b_dim,
2607              min_br = 255 * MIN_BRIGHT,
2608              max_br = 255 * MAX_BRIGHT;
2609     Colormap colormap = XDefaultColormap( TVDISPLAY, TVSCREEN );
2610     TV_UINT16   color_tbl_rg[ MAX_CUBE_DIM ],
2611                 color_tbl_b [ MAX_CUBE_DIM ];
2612 
2613     /*  For now, keep it simple and allocate the largest cube we can  */
2614     for ( cube_idx = 0; cube_idx < XtNumber( Color_cubes ); cube_idx++ ) {
2615         memset( col, '\0', sizeof( col ) );
2616 
2617         r_dim = Color_cubes[ cube_idx ][0];
2618         g_dim = Color_cubes[ cube_idx ][1];
2619         b_dim = Color_cubes[ cube_idx ][2];
2620 
2621         num_col = r_dim * g_dim * b_dim;
2622         assert( num_col <= XtNumber( col ) );
2623 
2624         /*  Fill up the color cube  */
2625         for ( i = 0; i < r_dim; i++ ) {
2626             int val = i * (max_br-min_br) / (r_dim-1) + min_br;
2627             color_tbl_rg[i] = val | ( val << 8 );
2628         }
2629         for ( i = 0; i < b_dim; i++ ) {
2630             int val = i * (max_br-min_br) / (b_dim-1) + min_br;
2631             color_tbl_b[i]  = val | ( val << 8 );
2632         }
2633 
2634         i = 0;
2635         for ( r = 0; r < r_dim; r++ )
2636             for ( g = 0; g < g_dim; g++ )
2637                 for ( b = 0; b < b_dim; b++ )
2638                     col[ i  ].red   = color_tbl_rg[ r ],
2639                     col[ i  ].green = color_tbl_rg[ g ],
2640                     col[ i  ].blue  = color_tbl_b [ b ],
2641                     col[ i++].flags = DoRed | DoGreen | DoBlue;
2642 
2643         /*  Allocate cube in the colormap  */
2644         for ( i = 0; i < num_col; i++ )
2645             if ( !XAllocColor( TVDISPLAY, colormap, &col[i] ) )
2646                 break;
2647 
2648         /*  If couldn't, fall back on next smaller cube size  */
2649         if ( i >= num_col )
2650             break;
2651 
2652         SUPRINTF(( "Failed to alloc %ldx%ldx%ld color cube\n",
2653                    r_dim, g_dim, b_dim ));
2654         for ( i--; i >= 0; i-- )
2655             XFreeColors( TVDISPLAY, colormap, &col[i].pixel, 1, 0 );
2656     }
2657     if ( r_dim < 2 ) {
2658         fprintf( stderr, "Can't even get a %ldx%ldx%ld colormap..."
2659                  "bailing out\n", r_dim, g_dim, b_dim );
2660         exit(1);
2661     }
2662     SUPRINTF(( "%ldx%ldx%ld Color Cube Allocated\n",r_dim,g_dim,b_dim ));
2663 
2664     /*  Done.  Now allocate and fill in the VideoLib colormap definition  */
2665     *cmap = VIDEOLIBNewColormap( num_col );
2666     if ( !*cmap )
2667         TVUTILOutOfMemory();
2668 
2669     for ( i = 0; i < num_col; i++ ) {
2670       (*cmap)->color[i].pixel = col[ i ].pixel;
2671       (*cmap)->color[i].r     = col[ i ].red   >> 8;
2672       (*cmap)->color[i].g     = col[ i ].green >> 8;
2673       (*cmap)->color[i].b     = col[ i ].blue  >> 8;
2674     }
2675 
2676     (*cmap)->type   = COLORMAP_PREDEF_CUBE;
2677     (*cmap)->dim[0] = r_dim;
2678     (*cmap)->dim[1] = g_dim;
2679     (*cmap)->dim[2] = b_dim;
2680     (*cmap)->corners[0][0] =
2681     (*cmap)->corners[0][1] =
2682     (*cmap)->corners[0][2] = 0;
2683     (*cmap)->corners[1][0] =
2684     (*cmap)->corners[1][1] =
2685     (*cmap)->corners[1][2] = 255;
2686 }
2687 
2688 
2689 /**@BEGINFUNC**************************************************************
2690 
2691     Prototype  : void TVSCREENNewFrameHdlr(
2692                       TV_IMAGE *img )
2693 
2694     Purpose    : Called to handle display of a new frame when we're not
2695                  in direct-video mode.
2696 
2697                  This is where any conversion or quantization that needs
2698                  to be performed for display occurs.
2699 
2700     Programmer : 07-Mar-97  Randall Hopper
2701 
2702     Parameters : img      - I: captured image
2703 
2704     Returns    : None.
2705 
2706     Globals    : None.
2707 
2708  **@ENDFUNC*****************************************************************/
2709 
TVSCREENNewFrameHdlr(TV_IMAGE * img)2710 void TVSCREENNewFrameHdlr( TV_IMAGE *img )
2711 {
2712     TV_XSCREEN          *x        = &G_glob.x;
2713     TV_DISPLAY          *d        = &G_glob.display;
2714     TV_XIMAGE           *ximage   = &d->ximage;
2715     XVisualInfo         *v        = &x->visual[ x->active_visual ];
2716     TV_INT32             dst_Bpp;
2717     VL_IMAGE             src, dst;
2718 
2719 #ifdef TESTING
2720     TVCAPTUREStop( &G_glob.capture );
2721     sleep(1);
2722     signal( SIGUSR1, SIG_IGN );
2723 #endif
2724 
2725     /*  FIXME  */
2726     /*  First, if user just froze the video, save this freeze-frame off    */
2727     /*    in case they want to work with it later (e.g. save it to disk).  */
2728     if ( d->cap_mode == TV_CAPTURE_SINGLE ) {
2729         TV_UINT32 bytes = img->geom.w * img->geom.h * img->pix_geom.Bpp;
2730 
2731         free( d->image.buf );
2732         if ( (d->image.buf = malloc( bytes )) == NULL )
2733             TVUTILOutOfMemory();
2734         memcpy( d->image.buf, img->buf, bytes );
2735         memcpy( &d->image.geom, &img->geom, sizeof( d->image.geom ) );
2736         memcpy( &d->image.pix_geom, &img->pix_geom,
2737                 sizeof( d->image.pix_geom ) );
2738     }
2739 
2740     TVCAPTUREClearPendingFrames();
2741 
2742     /*  FIXME: For testing, hack-convert source image to videolib format.  */
2743     src.buf = img->buf;
2744     src.geom.x = img->geom.x;
2745     src.geom.y = img->geom.y;
2746     src.geom.w = img->geom.w;
2747     src.geom.h = img->geom.h;
2748     src.geom.bytes_per_line = img->geom.w * img->pix_geom.Bpp;
2749     src.pix_geom.type = VL_PIXELTYPE_RGB;
2750     src.pix_geom.rgb.direct_color = (img->pix_geom.Bpp != 8);
2751     src.pix_geom.rgb.Bpp          = img->pix_geom.Bpp;
2752     src.pix_geom.rgb.mask[0]      = img->pix_geom.mask[0];
2753     src.pix_geom.rgb.mask[1]      = img->pix_geom.mask[1];
2754     src.pix_geom.rgb.mask[2]      = img->pix_geom.mask[2];
2755     src.pix_geom.rgb.colormap     = NULL;
2756     src.pix_geom.rgb.swap_bytes   = img->pix_geom.swap_bytes;
2757     src.pix_geom.rgb.swap_shorts  = img->pix_geom.swap_shorts;
2758 
2759     /*  Create the GC if needed  */
2760     XUTILGetVisualBpp( TVDISPLAY, v, &dst_Bpp, NULL );
2761 
2762     if ( d->gc == NULL )
2763         d->gc = XCreateGC( TVDISPLAY, d->win, 0, NULL );
2764 
2765     /*  Make sure the XImage buf is ready for this frame res/depth  */
2766     TVSCREENPrepXImage( d, &img->geom, v );
2767 
2768     /*  Now fill in destination image format */
2769     dst.buf = ximage->ximg->data;
2770     dst.geom.x = src.geom.x;
2771     dst.geom.y = src.geom.y;
2772     dst.geom.w = ximage->geom.w;
2773     dst.geom.h = ximage->geom.h;
2774     dst.geom.bytes_per_line = ximage->ximg->bytes_per_line;
2775     dst.pix_geom.type = VL_PIXELTYPE_RGB;
2776     dst.pix_geom.rgb.direct_color = (v->class == TrueColor);
2777     dst.pix_geom.rgb.Bpp          = dst_Bpp;
2778     dst.pix_geom.rgb.mask[0]      = v->red_mask;
2779     dst.pix_geom.rgb.mask[1]      = v->green_mask;
2780     dst.pix_geom.rgb.mask[2]      = v->blue_mask;
2781     dst.pix_geom.rgb.colormap     = NULL;
2782     dst.pix_geom.rgb.swap_bytes   = ( ximage->ximg->byte_order == LSBFirst );
2783     dst.pix_geom.rgb.swap_shorts  = ( ximage->ximg->byte_order == LSBFirst )
2784                                     && ( dst_Bpp >= 4 );
2785 
2786     /*  If this is a -to-PseudoColor conversion, we need to allocate a  */
2787     /*    color cube.                                                   */
2788     if (( v->class == PseudoColor ) && ( v->depth == 8 )) {
2789 
2790       assert( src.pix_geom.rgb.Bpp == 2 );
2791 
2792       if ( !d->colormap )
2793         TVSCREENAllocColorCube( d, &d->colormap );
2794 
2795       dst.pix_geom.rgb.colormap = d->colormap;
2796     }
2797 
2798     /*  Do conversion  */
2799     VIDEOLIBConvertImage( &src, &dst );
2800 
2801     /*  Ok, ximage is ready for use  */
2802     d->ximage_use_for_expose = TRUE;
2803 
2804     /*  Blast the image onto the display  */
2805     TVSCREENRedrawVideoWin();
2806 }
2807 
2808 
2809 /**@BEGINFUNC**************************************************************
2810 
2811     Prototype  : void TVSCREENSetAspectLock(
2812                       TV_BOOL aspect_lock )
2813 
2814     Purpose    : Turn aspect lock on/off.  This setting allows Fxtv to
2815                  adjust the size of the video window after a resize to
2816                  insure that it stays roughly 4:3 aspect ratio like NTSC.
2817                  FIXME:  May need tweaks for PAL.
2818 
2819     Programmer : 07-Sep-97  Randall Hopper
2820 
2821     Parameters : aspect_lock - I: new aspect lock setting
2822 
2823     Returns    :
2824 
2825     Globals    : None.
2826 
2827  **@ENDFUNC*****************************************************************/
2828 
TVSCREENSetAspectLock(TV_BOOL aspect_lock)2829 void TVSCREENSetAspectLock(
2830          TV_BOOL aspect_lock )
2831 {
2832     TV_DISPLAY          *d        = &G_glob.display;
2833 
2834     d->aspect_lock = (aspect_lock != FALSE);
2835 
2836     /*  If window is mapped and aspect lock is on, adjust video window geom  */
2837     if (( d->win != None ) && d->aspect_lock ) {
2838 
2839         if ( abs( d->geom.h * 4 / 3 - d->geom.w ) > 1 )
2840             TVSCREENSetVideoWinGeom( d->geom );
2841     }
2842 }
2843 
TVSCREENGetAspectLock(TV_BOOL * aspect_lock)2844 void TVSCREENGetAspectLock(
2845          TV_BOOL *aspect_lock )
2846 {
2847     TV_DISPLAY          *d        = &G_glob.display;
2848 
2849     *aspect_lock = d->aspect_lock;
2850 }
2851