1 /*
2 * annot.c
3 *
4 * Routines to manage the display of annotation on top of the video window.
5 *
6 * (C) 1997 Randall Hopper
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met: 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 2.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 /* ******************** Include Files ************** */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <sys/time.h>
37 #include <X11/Xlib.h>
38 #include "tvdefines.h"
39 #include "tvtypes.h"
40 #include "app_rsrc.h"
41 #include "annot.h"
42 #include "glob.h"
43 #include "tvutil.h"
44 #include "tvscreen.h"
45 #include "tvaudio.h"
46 #include "tvcapture.h"
47
48 /* ******************** Local defines ************** */
49
50 #define TIMEBASE_SEC 876000000L
51
52 #define FALLBACK_FONT "10x20"
53
54 #define QUANTIZE_FONT_SIZE(size) MAX( ((TV_INT32)(size)+4)/5*5, 10 )
55 /* Let's not go nuts creating different font sizes. They */
56 /* use memory and take CPU to compute. */
57
58 #define AUTOMODE_TIMER_MS 8
59
60 #define VOLUME_FMT "Volume: %ld%%"
61 #define MUTE_STR "MUTE"
62
63 /*#define FNPRINTF(x) printf x*/
64 #define FNPRINTF(x)
65
66 /* ******************** Forward declarations ************** */
67 /* ******************** Private variables ************** */
68 /* ******************** Function Definitions ************** */
69
70 /**@BEGINFUNC**************************************************************
71
72 Prototype : static void TVANNOTLoadFont(
73 Display *display,
74 char font[],
75 TV_INT32 pixel_size,
76 XFontSet *fontset )
77
78 Purpose : Loads the specified font pattern in the specified pixel_size,
79 if possible.
80
81 If multiple fonts match the pattern, the first match is
82 loaded.
83
84 If the first match is not an XLFD font with '0' or '*' in
85 the pixel_size component, pixel_size is ignored and the
86 font is loaded as-is.
87
88 If the font is invalid, a fallback font is loaded.
89
90 Programmer : 04-Oct-97 Randall Hopper
91
92 Parameters : display - I: X display
93 font - I: font pattern. Examples:
94 -*-utopia-regular-r-*-*-0-0-*-*-*-0-iso8859-1
95 9x15
96 pixel_size - I: desired pixel size to load font in
97 fontset - O: fontset handle to the loaded font
98
99 Returns : None.
100
101 Globals : None.
102
103 **@ENDFUNC*****************************************************************/
104
TVANNOTLoadFont(Display * display,char font[],TV_INT32 pixel_size,XFontSet * fontset)105 static void TVANNOTLoadFont(
106 Display *display,
107 char font[],
108 TV_INT32 pixel_size,
109 XFontSet *fontset )
110 {
111 char **fonts;
112 int count;
113 char new_font[ 256 ] = "";
114 XFontStruct *fontstr = NULL;
115 char **missing_charset_list;
116 int missing_count;
117
118 *fontset = NULL;
119
120 FNPRINTF(( "Validating font spec '%s'\n", font ));
121
122 fonts = XListFonts( display, font, 1, &count );
123
124 if ( count == 0 )
125 fprintf( stderr,
126 "No matching font(s) registered with X Server:\n %s\n", font );
127 else if ( XUTILIsWellFormedXLFDFont( fonts[0] ) ) {
128 FNPRINTF(( "Found at least one registered font, and the first "
129 "one is an XLFD font:\n '%s'\n", fonts[0] ));
130 FNPRINTF(( "Trying to load a '%d' pixel size version\n",
131 pixel_size ));
132
133 fontstr = XUTILLoadPixelSizeFont( TVDISPLAY, fonts[0], pixel_size,
134 new_font, sizeof(new_font) );
135
136 if ( fontstr == NULL ) {
137 new_font[0] = '\0';
138 fprintf( stderr, "Load failed:\n %s\n", fonts[0] );
139 }
140 else {
141 XFreeFontInfo( NULL, fontstr, 0 );
142 FNPRINTF(( "Load successful: '%s'\n", new_font ));
143 }
144 }
145 else {
146 FNPRINTF(( "Found at least one registered font; the first "
147 "one isn't an XLFD font:\n '%s'\n", fonts[0] ));
148
149 strncat( new_font, fonts[0], sizeof(new_font)-1 );
150 fontstr = XLoadQueryFont( TVDISPLAY, fonts[0] );
151
152 if ( fontstr == NULL )
153 new_font[0] = '\0';
154 else
155 XFreeFontInfo( NULL, fontstr, 0 );
156
157 if ( fontstr )
158 FNPRINTF(( "Load successful.\n" ));
159 else
160 fprintf( stderr, "Load failed:\n %s\n", fonts[0] );
161 }
162
163 if ( count )
164 XFreeFontNames( fonts );
165
166 if ( new_font[0] == '\0' ) {
167 strcpy( new_font, FALLBACK_FONT );
168 fprintf( stderr, "Falling back on '%s' font.\n", new_font );
169
170 fontstr = XLoadQueryFont( TVDISPLAY, new_font );
171 if ( fontstr == NULL ) {
172 fprintf( stderr,
173 "Failed to load the fall-back '%s' font.\n", new_font );
174 exit(1);
175 }
176 XFreeFontInfo( NULL, fontstr, 0 );
177 }
178
179 *fontset = XCreateFontSet( TVDISPLAY, new_font, &missing_charset_list,
180 &missing_count, NULL );
181 if ( ! *fontset ) {
182 fprintf( stderr,
183 "Whoah! Failed to load font '%s' which X 'said' it knew about.\n"
184 "This shouldn't happen (but does in XFree86 3.9.16).\n"
185 "Basically, choose another font or take the default font.\n",
186 new_font );
187 exit(1);
188 }
189 }
190
191 /*---------------------------------------------------------------------------*/
192
TVANNOTPropInit(TV_ANNOT_PROP * p)193 static void TVANNOTPropInit(
194 TV_ANNOT_PROP *p )
195 {
196 p->gc = NULL;
197 p->font_pattern = NULL;
198 p->fontset = NULL;
199 p->delay = 2000;
200 p->start_time.tv_sec = -1;
201 }
202
TVANNOTInit(TV_ANNOT * a,Display * display,int screen,XtAppContext app_context)203 void TVANNOTInit(
204 TV_ANNOT *a,
205 Display *display,
206 int screen,
207 XtAppContext app_context )
208 {
209 memset( a, '\0', sizeof(*a) );
210
211 a->display = display;
212 a->screen = screen;
213 a->app_context = app_context;
214 a->drawable = None;
215 a->geom.w =
216 a->geom.h = -1;
217 a->auto_update = False;
218
219 TVANNOTPropInit( &a->station );
220 TVANNOTPropInit( &a->tuner_mode );
221 TVANNOTPropInit( &a->input_dev );
222 TVANNOTPropInit( &a->volume );
223 TVANNOTPropInit( &a->mute );
224
225 /* Station */
226 a->station.delay = App_res.station_annot_delay;
227 a->station.font_pattern = App_res.station_annot_font;
228 a->station.fg_pixel = App_res.station_annot_color;
229
230 /* Tuner mode */
231 a->tuner_mode.delay = App_res.tuner_mode_annot_delay;
232 a->tuner_mode.font_pattern = App_res.tuner_mode_annot_font;
233 a->tuner_mode.fg_pixel = App_res.tuner_mode_annot_color;
234
235 /* Input Device */
236 a->input_dev.delay = App_res.input_dev_annot_delay;
237 a->input_dev.font_pattern = App_res.input_dev_annot_font;
238 a->input_dev.fg_pixel = App_res.input_dev_annot_color;
239
240 /* Volume */
241 a->volume.delay = App_res.volume_annot_delay;
242 a->volume.font_pattern = App_res.volume_annot_font;
243 a->volume.fg_pixel = App_res.volume_annot_color;
244
245 /* Mute */
246 a->mute.delay = App_res.mute_annot_delay;
247 a->mute.font_pattern = App_res.mute_annot_font;
248 a->mute.fg_pixel = App_res.mute_annot_color;
249 }
250
251 /*---------------------------------------------------------------------------*/
252
TVANNOTPropSetDrawable(TV_ANNOT_PROP * p,Display * display,Drawable drawable)253 static void TVANNOTPropSetDrawable(
254 TV_ANNOT_PROP *p,
255 Display *display,
256 Drawable drawable )
257 {
258 if ( p->gc != NULL )
259 XFreeGC( display, p->gc );
260 p->gc = XCreateGC( display, drawable, 0, NULL );
261 }
262
263
TVANNOTSetDrawable(TV_ANNOT * a,Drawable drawable)264 void TVANNOTSetDrawable(
265 TV_ANNOT *a,
266 Drawable drawable )
267 {
268 if ( a->drawable == drawable )
269 return;
270 a->drawable = drawable;
271
272 a->geom.w =
273 a->geom.h = -1;
274
275 /* When the drawable is set or changes, we need to recreate the GCs */
276 TVANNOTPropSetDrawable( &a->station , a->display, drawable );
277 TVANNOTPropSetDrawable( &a->tuner_mode, a->display, drawable );
278 TVANNOTPropSetDrawable( &a->input_dev , a->display, drawable );
279 TVANNOTPropSetDrawable( &a->volume , a->display, drawable );
280 TVANNOTPropSetDrawable( &a->mute , a->display, drawable );
281 }
282
283 /*---------------------------------------------------------------------------*/
284
TVANNOTGetModeGeom(Dimension * width,Dimension * height)285 static void TVANNOTGetModeGeom(
286 Dimension *width,
287 Dimension *height )
288 {
289 TV_XSCREEN *s = &G_glob.x;
290
291 if ( s->vmode_ext_supported )
292 TVSCREENGetCurVidModeGeometry( s, width, height );
293 else
294 *width = DisplayWidth ( TVDISPLAY, TVSCREEN ),
295 *height = DisplayHeight( TVDISPLAY, TVSCREEN );
296 }
297
298
TVANNOTStationPropSetDrawableSize(TV_ANNOT * a,TV_ANNOT_PROP * p,Display * display,Dimension width,Dimension height)299 static void TVANNOTStationPropSetDrawableSize(
300 TV_ANNOT *a,
301 TV_ANNOT_PROP *p,
302 Display *display,
303 Dimension width,
304 Dimension height )
305 {
306 TV_INT32 pixel_size;
307 Dimension vm_width,
308 vm_height;
309 XFontSetExtents *extents;
310
311 /* Determine new pixel size based on Drawable size and Video Mode */
312 TVANNOTGetModeGeom( &vm_width, &vm_height );
313 pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 15 );
314
315 /* If different than the one we've got, reload at the new size */
316 if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) {
317
318 FNPRINTF(( "\nSTATION ANNOTATION FONT:\n" ));
319
320 if ( p->fontset != NULL )
321 XFreeFontSet( display, p->fontset );
322
323 TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset );
324 assert( p->fontset != NULL );
325
326 p->pixel_size = pixel_size;
327 }
328
329 /* Determine new location */
330 extents = XExtentsOfFontSet( p->fontset );
331 p->loc.x = 15;
332 p->loc.y = height - 15;
333 }
334
335
TVANNOTTunerModePropSetDrawableSize(TV_ANNOT * a,TV_ANNOT_PROP * p,Display * display,Dimension width,Dimension height)336 static void TVANNOTTunerModePropSetDrawableSize(
337 TV_ANNOT *a,
338 TV_ANNOT_PROP *p,
339 Display *display,
340 Dimension width,
341 Dimension height )
342 {
343 TV_INT32 pixel_size;
344 Dimension vm_width,
345 vm_height;
346 XFontSetExtents *extents;
347
348 /* Determine new pixel size based on Drawable size and Video Mode */
349 TVANNOTGetModeGeom( &vm_width, &vm_height );
350 pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 20 );
351
352 /* If different than the one we've got, reload at the new size */
353 if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) {
354
355 FNPRINTF(( "\nTUNER MODE ANNOTATION FONT:\n" ));
356
357 if ( p->fontset != NULL )
358 XFreeFontSet( display, p->fontset );
359
360 TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset );
361 assert( p->fontset != NULL );
362
363 p->pixel_size = pixel_size;
364 }
365
366 /* Determine new location */
367 extents = XExtentsOfFontSet( p->fontset );
368 p->loc.x = 15;
369 p->loc.y = 5 + extents->max_logical_extent.height;
370 }
371
372
TVANNOTInputDevPropSetDrawableSize(TV_ANNOT * a,TV_ANNOT_PROP * p,Display * display,Dimension width,Dimension height)373 static void TVANNOTInputDevPropSetDrawableSize(
374 TV_ANNOT *a,
375 TV_ANNOT_PROP *p,
376 Display *display,
377 Dimension width,
378 Dimension height )
379 {
380 TV_INT32 pixel_size;
381 Dimension vm_width,
382 vm_height;
383 XFontSetExtents *extents_tm,
384 *extents;
385
386 /* Determine new pixel size based on Drawable size and Video Mode */
387 TVANNOTGetModeGeom( &vm_width, &vm_height );
388 pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 20 );
389
390 /* If different than the one we've got, reload at the new size */
391 if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) {
392
393 FNPRINTF(( "\nINPUT DEVICE ANNOTATION FONT:\n" ));
394
395 if ( p->fontset != NULL )
396 XFreeFontSet( display, p->fontset );
397
398 TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset );
399 assert( p->fontset != NULL );
400
401 p->pixel_size = pixel_size;
402 }
403
404 /* Determine new location - put it below Tuner Mode annotation */
405 extents_tm = XExtentsOfFontSet( a->tuner_mode.fontset );
406 extents = XExtentsOfFontSet( p->fontset );
407 p->loc.x = 15;
408 p->loc.y = a->tuner_mode.loc.y +
409 extents_tm->max_logical_extent.height / 2 +
410 extents->max_logical_extent.height / 2;
411 }
412
413
TVANNOTVolumePropSetDrawableSize(TV_ANNOT * a,TV_ANNOT_PROP * p,Display * display,Dimension width,Dimension height)414 static void TVANNOTVolumePropSetDrawableSize(
415 TV_ANNOT *a,
416 TV_ANNOT_PROP *p,
417 Display *display,
418 Dimension width,
419 Dimension height )
420 {
421 TV_INT32 pixel_size;
422 Dimension vm_width,
423 vm_height;
424 XFontSetExtents *extents;
425 char str[80];
426 int str_width;
427
428 /* Determine new pixel size based on Drawable size and Video Mode */
429 TVANNOTGetModeGeom( &vm_width, &vm_height );
430 pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 20 );
431
432 /* If different than the one we've got, reload at the new size */
433 if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) {
434
435 FNPRINTF(( "\nVOLUME ANNOTATION FONT:\n" ));
436
437 if ( p->fontset != NULL )
438 XFreeFontSet( display, p->fontset );
439
440 TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset );
441 assert( p->fontset != NULL );
442
443 p->pixel_size = pixel_size;
444 }
445
446 /* Determine new location */
447 sprintf( str, VOLUME_FMT, 100L );
448 str_width = XmbTextEscapement( p->fontset, str, strlen(str) );
449 extents = XExtentsOfFontSet( p->fontset );
450
451 p->loc.x = width - 15 - str_width;
452 p->loc.y = 5 + extents->max_logical_extent.height;
453 }
454
455
TVANNOTMutePropSetDrawableSize(TV_ANNOT * a,TV_ANNOT_PROP * p,Display * display,Dimension width,Dimension height)456 static void TVANNOTMutePropSetDrawableSize(
457 TV_ANNOT *a,
458 TV_ANNOT_PROP *p,
459 Display *display,
460 Dimension width,
461 Dimension height )
462 {
463 TV_INT32 pixel_size;
464 Dimension vm_width,
465 vm_height;
466 XFontSetExtents *extents_v,
467 *extents;
468 int str_width;
469
470 /* Determine new pixel size based on Drawable size and Video Mode */
471 TVANNOTGetModeGeom( &vm_width, &vm_height );
472 pixel_size = QUANTIZE_FONT_SIZE( (TV_INT32)height * vm_height / 768 / 25 );
473
474 /* If different than the one we've got, reload at the new size */
475 if (( p->fontset == NULL ) || ( p->pixel_size != pixel_size )) {
476
477 FNPRINTF(( "\nMUTE ANNOTATION FONT:\n" ));
478
479 if ( p->fontset != NULL )
480 XFreeFontSet( display, p->fontset );
481
482 TVANNOTLoadFont( display, p->font_pattern, pixel_size, &p->fontset );
483 assert( p->fontset != NULL );
484
485 p->pixel_size = pixel_size;
486 }
487
488 /* Determine new location - Put below Volume Annotation */
489 str_width = XmbTextEscapement( p->fontset, MUTE_STR, strlen(MUTE_STR) );
490 extents_v = XExtentsOfFontSet( a->volume.fontset );
491 extents = XExtentsOfFontSet( p->fontset );
492
493 p->loc.x = width - 15 - str_width;
494 p->loc.y = a->volume.loc.y +
495 extents_v->max_logical_extent.height / 2 +
496 extents->max_logical_extent.height / 2;
497 }
498
499
TVANNOTSetDrawableSize(TV_ANNOT * a,Dimension width,Dimension height)500 void TVANNOTSetDrawableSize(
501 TV_ANNOT *a,
502 Dimension width,
503 Dimension height )
504 {
505 Display *d = a->display;
506
507 a->geom.w = width;
508 a->geom.h = height;
509
510 TVANNOTStationPropSetDrawableSize ( a, &a->station , d, width, height );
511 TVANNOTTunerModePropSetDrawableSize( a, &a->tuner_mode, d, width, height );
512 TVANNOTInputDevPropSetDrawableSize ( a, &a->input_dev , d, width, height );
513 TVANNOTVolumePropSetDrawableSize ( a, &a->volume , d, width, height );
514 TVANNOTMutePropSetDrawableSize ( a, &a->mute , d, width, height );
515 }
516
517
518 /*---------------------------------------------------------------------------*/
519
TVANNOTUpdateIsRequired(TV_ANNOT_PROP * p,struct timeval * cur_time)520 static TV_BOOL TVANNOTUpdateIsRequired(
521 TV_ANNOT_PROP *p,
522 struct timeval *cur_time )
523 {
524 TV_BOOL required;
525 TV_INT32 elapsed = -1;
526
527 if (( p->delay > 0 ) && ( p->start_time.tv_sec >= 0 ))
528 elapsed = ( cur_time->tv_usec - p->start_time.tv_usec ) / 1000 +
529 ( cur_time->tv_sec - p->start_time.tv_sec ) * 1000;
530
531 required = ( p->delay < 0 ) ||
532 (( elapsed >= 0 ) && ( elapsed <= p->delay ));
533
534 if ( !required )
535 p->start_time.tv_sec = -1;
536
537 return required;
538 }
539
TVANNOTDrawShadowedText(TV_ANNOT * a,TV_ANNOT_PROP * p,char str[])540 static void TVANNOTDrawShadowedText(
541 TV_ANNOT *a,
542 TV_ANNOT_PROP *p,
543 char str[] )
544 {
545 XGCValues gcv;
546 XtGCMask gcmask;
547
548 gcmask = GCForeground;
549 gcv.foreground = BlackPixel( a->display, a->screen );
550 XChangeGC( a->display, p->gc, gcmask, &gcv );
551
552 XmbDrawString( a->display, a->drawable, p->fontset, p->gc,
553 p->loc.x+1, p->loc.y+1, str, strlen(str) );
554
555 gcv.foreground = p->fg_pixel;
556 XChangeGC( a->display, p->gc, gcmask, &gcv );
557
558 XmbDrawString( a->display, a->drawable, p->fontset, p->gc,
559 p->loc.x, p->loc.y, str, strlen(str) );
560 }
561
562
TVANNOTStationPropUpdate(TV_ANNOT * a,struct timeval * cur_time,TV_ANNOT_PROP * p)563 static TV_BOOL TVANNOTStationPropUpdate(
564 TV_ANNOT *a,
565 struct timeval *cur_time,
566 TV_ANNOT_PROP *p )
567 {
568 TV_CAPTURE *c = &G_glob.capture;
569 TV_DRIVER_STATE state;
570 TV_STATION *station;
571 char chan_str[ 80 ];
572
573 /* First, see if we even need to display */
574 if ( !TVANNOTUpdateIsRequired( p, cur_time ) )
575 return FALSE;
576
577 /* Paranoid sanity check */
578 assert((p->gc != NULL ) && ( p->fontset != NULL ));
579
580 /* Query driver state (freq or channel) */
581 /* FIXME: Add CAPTURE interface to just query indiv params */
582 if ( !TVCAPTUREQueryDriverState( c, &state ) ) {
583 fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" );
584 exit(1);
585 }
586
587 /* Figure out which station we're on (if any) */
588 TVSTATIONLookup( &state, &station );
589
590 /* Format station text */
591 if ( station != NULL ) {
592 if ( station->set_via_channel ) {
593 sprintf( chan_str, "%d", station->channel );
594 if ( strcmp( station->id, chan_str ) != 0 ) {
595 if ( App_res.station_annot_idonly )
596 sprintf( chan_str, "%s", station->id );
597 else
598 sprintf( chan_str, "%s (%d)", station->id,
599 station->channel );
600 }
601 }
602 else
603 if ( App_res.station_annot_idonly )
604 sprintf( chan_str, "%s", station->id );
605 else
606 sprintf( chan_str, "%s (%.2f MHz)", station->id,
607 station->freq );
608 }
609 else if ( state.tuner_chan_active )
610 sprintf( chan_str, "%ld", state.tuner_chan );
611 else
612 sprintf( chan_str, "%.2f MHz", state.tuner_freq );
613
614 /* And display it */
615 TVANNOTDrawShadowedText( a, p, chan_str );
616
617 return TRUE;
618 }
619
620
TVANNOTTunerModePropUpdate(TV_ANNOT * a,struct timeval * cur_time,TV_ANNOT_PROP * p)621 static TV_BOOL TVANNOTTunerModePropUpdate(
622 TV_ANNOT *a,
623 struct timeval *cur_time,
624 TV_ANNOT_PROP *p )
625 {
626 TV_PREFS *prefs = &G_glob.prefs;
627 char *str;
628
629 /* First, see if we even need to display */
630 if ( !TVANNOTUpdateIsRequired( p, cur_time ) )
631 return FALSE;
632
633 /* Paranoid sanity check */
634 assert((p->gc != NULL ) && ( p->fontset != NULL ));
635
636 /* Format text */
637 switch ( prefs->tuner_mode ) {
638 case TV_TUNER_MODE_ANTENNA : str = "ANTENNA"; break;
639 case TV_TUNER_MODE_CABLE : str = "CABLE"; break;
640 default :
641 fprintf( stderr, "TVANNOTTunerModePropUpdate: Unknown mode\n" );
642 exit(1);
643 }
644
645 /* And display it */
646 TVANNOTDrawShadowedText( a, p, str );
647
648 return TRUE;
649 }
650
651
TVANNOTInputDevPropUpdate(TV_ANNOT * a,struct timeval * cur_time,TV_ANNOT_PROP * p)652 static TV_BOOL TVANNOTInputDevPropUpdate(
653 TV_ANNOT *a,
654 struct timeval *cur_time,
655 TV_ANNOT_PROP *p )
656 {
657 TV_CAPTURE *c = &G_glob.capture;
658 TV_DRIVER_STATE state;
659 char *str;
660
661 /* First, see if we even need to display */
662 if ( !TVANNOTUpdateIsRequired( p, cur_time ) )
663 return FALSE;
664
665 /* Paranoid sanity check */
666 assert((p->gc != NULL ) && ( p->fontset != NULL ));
667
668 /* Query driver state (input device) */
669 /* FIXME: Add CAPTURE interface to just query indiv params */
670 if ( !TVCAPTUREQueryDriverState( c, &state ) ) {
671 fprintf( stderr, "TVCAPTUREQueryDriverState() failed\n" );
672 exit(1);
673 }
674
675 /* Format text */
676 switch ( state.input_dev ) {
677 case TV_DEVICE_TUNER : str = "TUNER IN" ; break;
678 case TV_DEVICE_VIDEO : str = "VIDEO IN" ; break;
679 case TV_DEVICE_SVIDEO : str = "SVIDEO IN" ; break;
680 case TV_DEVICE_CSVIDEO : str = "CSVIDEO IN"; break;
681 default :
682 fprintf( stderr, "TVANNOTInputDevPropUpdate: Bad device\n" );
683 exit(1);
684 }
685
686 /* And display it */
687 TVANNOTDrawShadowedText( a, p, str );
688
689 return TRUE;
690 }
691
692
TVANNOTVolumePropUpdate(TV_ANNOT * a,struct timeval * cur_time,TV_ANNOT_PROP * p)693 static TV_BOOL TVANNOTVolumePropUpdate(
694 TV_ANNOT *a,
695 struct timeval *cur_time,
696 TV_ANNOT_PROP *p )
697 {
698 TV_INT32 vol;
699 char str[80];
700
701 /* First, see if we even need to display */
702 if ( !TVANNOTUpdateIsRequired( p, cur_time ) )
703 return FALSE;
704
705 /* Paranoid sanity check */
706 assert((p->gc != NULL ) && ( p->fontset != NULL ));
707
708 /* Query current line volume */
709 TVAUDIOGetLineVolume( &vol );
710
711 /* Format text */
712 sprintf( str, VOLUME_FMT, vol );
713
714 /* And display it */
715 TVANNOTDrawShadowedText( a, p, str );
716
717 return TRUE;
718 }
719
720
TVANNOTMutePropUpdate(TV_ANNOT * a,struct timeval * cur_time,TV_ANNOT_PROP * p)721 static TV_BOOL TVANNOTMutePropUpdate(
722 TV_ANNOT *a,
723 struct timeval *cur_time,
724 TV_ANNOT_PROP *p )
725 {
726 TV_BOOL mute_on;
727 char *str;
728
729 /* Query current mute state */
730 TVAUDIOGetMuteState( &mute_on );
731
732 /* See if we even need to display */
733 if ( !mute_on || !TVANNOTUpdateIsRequired( p, cur_time ) )
734 return FALSE;
735
736 /* Paranoid sanity check */
737 assert((p->gc != NULL ) && ( p->fontset != NULL ));
738
739 /* Format text */
740 str = mute_on ? MUTE_STR : "";
741
742 /* And display it */
743 TVANNOTDrawShadowedText( a, p, str );
744
745 return TRUE;
746 }
747
748
749 /**@BEGINFUNC**************************************************************
750
751 Prototype : TV_BOOL TVANNOTUpdate(
752 TV_ANNOT *a )
753
754 Purpose : Give annotations a chance to update. Returns TRUE if
755 any annotations were active and thus needed to be
756 drawn.
757
758 Programmer : 05-Oct-97 Randall Hopper
759
760 Parameters : a - I: annotation def
761
762 Returns : T = something was drawn; F = nothing drawn
763
764 Globals : None.
765
766 **@ENDFUNC*****************************************************************/
767
TVANNOTUpdate(TV_ANNOT * a)768 TV_BOOL TVANNOTUpdate(
769 TV_ANNOT *a )
770 {
771 struct timeval tv;
772 TV_BOOL changed = FALSE,
773 ch[5];
774
775 /* If drawable and its size haven't been set yet, no action */
776 if (( a->drawable == None ) || ( a->geom.w < 0 ))
777 return FALSE;
778
779 /* Compute current time (in msec) */
780 gettimeofday( &tv, NULL );
781
782 /* Update all annotation properties */
783 ch[0] = TVANNOTStationPropUpdate ( a, &tv, &a->station );
784 ch[1] = TVANNOTTunerModePropUpdate( a, &tv, &a->tuner_mode );
785 ch[2] = TVANNOTInputDevPropUpdate ( a, &tv, &a->input_dev );
786 ch[3] = TVANNOTVolumePropUpdate ( a, &tv, &a->volume );
787 ch[4] = TVANNOTMutePropUpdate ( a, &tv, &a->mute );
788
789 changed = ch[0] || ch[1] || ch[2] || ch[3] || ch[4];
790
791 return changed;
792 }
793
794 /*---------------------------------------------------------------------------*/
795
TVANNOTUpdateTimeoutCB(XtPointer cl_data,XtIntervalId * timer)796 static void TVANNOTUpdateTimeoutCB(
797 XtPointer cl_data,
798 XtIntervalId *timer )
799 {
800 TV_BOOL changed;
801 TV_ANNOT *a = (TV_ANNOT *) cl_data;
802
803 a->timer_set = FALSE;
804
805 /* If somebody killed auto-update mode, bail */
806 if ( !a->auto_update )
807 return;
808
809 changed = TVANNOTUpdate( a );
810
811 /* If anything changed, reregister our timer */
812 if ( changed ) {
813 a->timer = XtAppAddTimeOut( a->app_context, AUTOMODE_TIMER_MS,
814 TVANNOTUpdateTimeoutCB, a );
815 a->timer_set = TRUE;
816 }
817 }
818
819
820 /**@BEGINFUNC**************************************************************
821
822 Prototype : void TVANNOTSetAutoUpdateMode(
823 TV_ANNOT *a,
824 TV_BOOL enabled )
825
826 Purpose : The annotation module can be set in one of two different
827 modes:
828
829 1) AutoUpdate OFF means the client has to call TVANNOTUpdate
830 manually to add the annotation to the registered drawable
831 If no annotation is pending, the call is a no-op.
832
833 2) AutoUpdate ON means that this module sets a timer and
834 periodically calls TVANNOTUpdate itself. The timer is
835 only registered when annotation is pending. After all
836 annotation expires, the timer is canceled.
837
838 Programmer : 05-Oct-97 Randall Hopper
839
840 Parameters : a - I: annotation def
841 enabled - I: new state for auto-update mode
842
843 Returns : None.
844
845 Globals : None.
846
847 **@ENDFUNC*****************************************************************/
848
TVANNOTSetAutoUpdateMode(TV_ANNOT * a,TV_BOOL enabled)849 void TVANNOTSetAutoUpdateMode(
850 TV_ANNOT *a,
851 TV_BOOL enabled )
852 {
853 enabled = (enabled != 0);
854
855 if ( a->auto_update == enabled )
856 return;
857
858 a->auto_update = enabled;
859
860 /* If leaving auto-update, kill timer */
861 if ( !a->auto_update ) {
862 if ( a->timer_set ) {
863 XtRemoveTimeOut( a->timer );
864 a->timer_set = FALSE;
865 }
866 }
867
868 /* Else entering auto-update; start timer */
869 else {
870 a->timer = XtAppAddTimeOut( a->app_context, AUTOMODE_TIMER_MS,
871 TVANNOTUpdateTimeoutCB, a );
872 a->timer_set = TRUE;
873 }
874 }
875
876
877 /*---------------------------------------------------------------------------*/
878
TVANNOTSignalPropChange(TV_ANNOT * a,TV_ANNOT_TYPE type)879 void TVANNOTSignalPropChange(
880 TV_ANNOT *a,
881 TV_ANNOT_TYPE type )
882 {
883 struct timeval tv;
884 TV_ANNOT_PROP *p;
885
886 gettimeofday( &tv, NULL );
887
888 switch ( type ) {
889 case TV_ANNOT_TYPE_STATION : p = &a->station ; break;
890 case TV_ANNOT_TYPE_TUNER_MODE : p = &a->tuner_mode; break;
891 case TV_ANNOT_TYPE_INPUT_DEV : p = &a->input_dev ; break;
892 case TV_ANNOT_TYPE_VOLUME : p = &a->volume ; break;
893 case TV_ANNOT_TYPE_MUTE : p = &a->mute ; break;
894 default :
895 fprintf( stderr, "TVANNOTSignalPropChange: Bad type\n" );
896 exit(1);
897 }
898
899 memcpy( &p->start_time, &tv, sizeof(tv) );
900
901 /* If we're in auto-update mode, start the auto-update timer */
902 if ( a->auto_update && !a->timer_set ) {
903 a->timer = XtAppAddTimeOut( a->app_context, AUTOMODE_TIMER_MS,
904 TVANNOTUpdateTimeoutCB, a );
905 a->timer_set = TRUE;
906 }
907 }
908
909