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