]> git.sesse.net Git - vlc/blob - plugins/macosx/vout_macosx.c
Cleaning code and a small fix to make quit work on OSX
[vlc] / plugins / macosx / vout_macosx.c
1 /*****************************************************************************
2  * vout_macosx.c: MacOS X video output plugin
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  *
6  * Authors: 
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #define MODULE_NAME macosx
24 #include "modules_inner.h"
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "defs.h"
30
31 #include <errno.h>                                                 /* ENOMEM */
32 #include <stdlib.h>                                                /* free() */
33 #include <string.h>                                            /* strerror() */
34
35 #include "config.h"
36 #include "common.h"
37 #include "threads.h"
38 #include "mtime.h"
39 #include "tests.h"
40
41 #include "video.h"
42 #include "video_output.h"
43
44 #include "intf_msg.h"
45
46 #include "main.h"
47
48 #include "modules.h"
49
50 #ifndef __CARBONPREFIX__
51     #define __CARBONPREFIX__
52
53     // Needed for carbonization
54     #define TARGET_API_MAC_CARBON 1
55
56     // For the pascal to C or C to pascal string conversions in carbon
57     #define OLDP2C 1
58 #endif
59
60 #include <Carbon/Carbon.h>
61
62 // Initial Window Constants
63 enum
64 {
65     kWindowOffset = 100
66 };
67
68 // where is the off screen
69 enum
70 {
71     kNoWhere = 0,
72     kInVRAM,
73     kInAGP,
74     kInSystem
75 };
76
77 /*****************************************************************************
78  * vout_sys_t: MacOS X video output method descriptor
79  *****************************************************************************
80  * This structure is part of the video output thread descriptor.
81  * It describes the MacOS X specific properties of an output thread.
82  *****************************************************************************/
83 typedef struct vout_sys_s
84 {
85     /* MacOS X video memory */
86     byte_t *                    p_video;                      /* base adress */
87     size_t                      i_page_size;                    /* page size */
88     
89     Rect        wrect;
90     WindowRef   p_window;
91     short gwLocOffscreen;
92     GWorldPtr p_gw[ 2 ];
93     Boolean gNewNewGWorld;      /* can we allocate in VRAm or AGP memory ? */
94     
95     // Boolean gDone;
96     // SInt32 gSleepTime;
97     
98     GDHandle  theGDList;
99     Ptr                         theBase;
100     int                         theRow;
101     int                         theDepth;
102 } vout_sys_t;
103
104 /*****************************************************************************
105  * Local prototypes
106  *****************************************************************************/
107 static int  vout_Probe     ( probedata_t *p_data );
108 static int  vout_Create    ( struct vout_thread_s * );
109 static int  vout_Init      ( struct vout_thread_s * );
110 static void vout_End       ( struct vout_thread_s * );
111 static void vout_Destroy   ( struct vout_thread_s * );
112 static int  vout_Manage    ( struct vout_thread_s * );
113 static void vout_Display   ( struct vout_thread_s * );
114
115 /* OS specific */
116
117 static int CreateDisplay        ( struct vout_thread_s * );
118 static int MakeWindow           ( struct vout_thread_s * );
119 static int AllocBuffer          ( struct vout_thread_s * , short index );
120
121 void BlitToWindow               ( struct vout_thread_s * , short index );
122 GDHandle GetWindowDevice        ( struct vout_thread_s * );
123 void FillOffscreen              ( struct vout_thread_s * , short index);
124
125 void FindBestMemoryLocation( struct vout_thread_s * );
126
127 /*****************************************************************************
128  * Functions exported as capabilities. They are declared as static so that
129  * we don't pollute the namespace too much.
130  *****************************************************************************/
131 void _M( vout_getfunctions )( function_list_t * p_function_list )
132 {
133     p_function_list->pf_probe = vout_Probe;
134     p_function_list->functions.vout.pf_create     = vout_Create;
135     p_function_list->functions.vout.pf_init       = vout_Init;
136     p_function_list->functions.vout.pf_end        = vout_End;
137     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
138     p_function_list->functions.vout.pf_manage     = vout_Manage;
139     p_function_list->functions.vout.pf_display    = vout_Display;
140     p_function_list->functions.vout.pf_setpalette = NULL;
141 }
142
143 /*****************************************************************************
144  * intf_Probe: return a score
145  *****************************************************************************/
146 static int vout_Probe( probedata_t *p_data )
147 {
148     if( TestMethod( VOUT_METHOD_VAR, "macosx" ) )
149     {
150         return( 999 );
151     }
152
153     return( 100 );
154 }
155
156 /*****************************************************************************
157  * vout_Create: allocates MacOS X video thread output method
158  *****************************************************************************
159  * This function allocates and initializes a MacOS X vout method.
160  *****************************************************************************/
161 static int vout_Create( vout_thread_t *p_vout )
162 {
163     //intf_ErrMsg( "vout_Create()" );
164
165     /* Allocate structure */
166     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
167     if( p_vout->p_sys == NULL )
168     {
169         intf_ErrMsg( "error: %s", strerror( ENOMEM ) );
170         return( 1 );
171     }
172
173     p_vout->p_sys->gwLocOffscreen = kNoWhere;
174     p_vout->p_sys->p_window       = NULL;
175     p_vout->p_sys->p_gw[ 0 ]      = NULL;
176     p_vout->p_sys->p_gw[ 1 ]      = NULL;
177     p_vout->p_sys->i_page_size    = p_vout->i_width * p_vout->i_height
178                                   * p_vout->i_bytes_per_pixel;
179     
180     if ( CreateDisplay( p_vout ) )
181     {
182         intf_ErrMsg( "vout error: can't open display" );
183         free( p_vout->p_sys );
184         return( 1 );
185     }
186
187 #if 0
188     intf_ErrMsg( "vout p_vout->i_width %d" , p_vout->i_width);
189     intf_ErrMsg( "vout p_vout->i_height %d" , p_vout->i_height);
190     intf_ErrMsg( "vout p_vout->i_bytes_per_pixel %d" , p_vout->i_bytes_per_pixel);
191     intf_ErrMsg( "vout p_vout->i_screen_depth %d" , p_vout->i_screen_depth);
192     intf_ErrMsg( "vout p_vout->p_sys->i_page_size %d" , p_vout->p_sys->i_page_size);
193 #endif
194
195 #if 0
196     /* Map two framebuffers a the very beginning of the fb */
197     p_vout->p_sys->p_video = malloc( 2 * p_vout->p_sys->i_page_size );
198     if( p_vout->p_sys->p_video == NULL )
199     {
200         intf_ErrMsg( "vout error: can't map video memory (%s)",
201                      strerror(errno) );
202         free( p_vout->p_sys );
203         return( 1 );
204     }
205     /* Set and initialize buffers */
206     vout_SetBuffers( p_vout, p_vout->p_sys->p_video,
207                     p_vout->p_sys->p_video + p_vout->p_sys->i_page_size );
208 #endif
209
210     return( 0 );
211 }
212
213 /*****************************************************************************
214  * Find the best memory (AGP, VRAM, system) location
215  *****************************************************************************/
216 void FindBestMemoryLocation( vout_thread_t *p_vout )
217 {
218     long versionSystem;
219
220     Gestalt( gestaltSystemVersion, &versionSystem );
221     if ( 0x00000900 <= ( versionSystem & 0x00000FF00  ) )
222     {
223         intf_ErrMsg( "FindBestMemoryLocation : gNewNewGWorld = true" );
224         p_vout->p_sys->gNewNewGWorld = true;
225     }
226     else
227     {
228         // now it is tricky
229         // we will try to allocate in VRAM and find out where the allocation really ended up.
230         GWorldPtr pgwTest = NULL;
231         Rect rectTest = {0, 0, 10, 10};
232         short wPixDepth = 
233             (**(GetPortPixMap( GetWindowPort( p_vout->p_sys->p_window ) ))).pixelSize;
234         GDHandle hgdWindow = GetWindowDevice( p_vout );
235
236         intf_ErrMsg( "FindBestMemoryLocation : gNewNewGWorld = false !" );
237 #if 0
238         p_vout->i_screen_depth = wPixDepth;
239         p_vout->i_bytes_per_pixel = wPixDepth;
240         p_vout->i_bytes_per_line   = p_vout->i_width * p_vout->i_bytes_per_pixel;
241         p_vout->p_sys->i_page_size = p_vout->i_width * p_vout->i_height * p_vout->i_bytes_per_pixel;
242 //p_vout->i_bytes_per_line = (**(**hgdWindow).gdPMap).rowBytes & 0x3FFF ;
243 #endif
244         if(    ( noErr == NewGWorld( &pgwTest, wPixDepth, &rectTest, NULL, hgdWindow,
245                                      noNewDevice | useDistantHdwrMem ) ) 
246             && ( pgwTest ) )
247         {
248             p_vout->p_sys->gNewNewGWorld = true;        
249         }
250         
251         if( pgwTest )
252         {
253             DisposeGWorld( pgwTest );
254         }
255     }
256 }
257
258 /*****************************************************************************
259  * CreateDisplay: setup display params...
260  *****************************************************************************/
261 static int CreateDisplay( vout_thread_t *p_vout )
262 {
263     PixMapHandle hPixmap0, hPixmap1;
264     void * hPixmapBaseAddr0, * hPixmapBaseAddr1;
265
266     //intf_ErrMsg( "CreateDisplay()" );
267
268     if( MakeWindow( p_vout ) )
269     {
270         intf_ErrMsg( "vout error: can't open window display" );
271         return( 1 );
272     }
273
274     // FindBestMemoryLocation( p_vout );
275
276     //try to allocate @ best location, will eventaully trickle down to worst
277     p_vout->p_sys->gwLocOffscreen = kInVRAM;
278     if( AllocBuffer( p_vout, 0 ) || AllocBuffer( p_vout, 1 ) )
279     {
280         intf_ErrMsg( "vout error: can't alloc offscreen buffers" );
281         return( 1 );
282     }
283
284 //FIXME ? - lock this down until the end...
285     hPixmap0 = GetGWorldPixMap( p_vout->p_sys->p_gw[0] );
286     LockPixels(hPixmap0);
287     hPixmap1 = GetGWorldPixMap( p_vout->p_sys->p_gw[1] );
288     LockPixels(hPixmap1);
289     
290     //FIXME hopefully this is the same for all Gworlds & window since they are the same size
291     p_vout->i_bytes_per_line = (**hPixmap0).rowBytes & 0x3FFF;
292
293     if ( (hPixmap0 == NULL) || (hPixmap1 == NULL) )
294     {
295         intf_ErrMsg( "vout error: pixmap problem");
296         UnlockPixels(hPixmap0);
297         UnlockPixels(hPixmap1);
298         return( 1 );
299     }
300
301     hPixmapBaseAddr0 = GetPixBaseAddr( hPixmap0 );
302     hPixmapBaseAddr1 = GetPixBaseAddr( hPixmap1 );
303     if ( (hPixmapBaseAddr0 == NULL) || (hPixmapBaseAddr1 == NULL) )
304     {
305         intf_ErrMsg( "vout error: pixmap base addr problem");
306         return( 1 );
307     }
308
309 //FIXME - if I ever dispose of the Gworlds and recreate them, i'll have a new address
310 //and I'll need to tell vout about them...  dunno what problems vout might have if we just updateGworld  
311     vout_SetBuffers( p_vout, hPixmapBaseAddr0, hPixmapBaseAddr1 );
312
313     return 0;
314 }
315
316 /*****************************************************************************
317  * MakeWindow: open and set-up a Mac OS main window
318  *****************************************************************************/
319 static int MakeWindow( vout_thread_t *p_vout )
320 {
321     int left = 0;
322     int top = 0;
323     int bottom = p_vout->i_height;
324     int right = p_vout->i_width;
325
326     WindowAttributes windowAttr = kWindowStandardDocumentAttributes | 
327                                     kWindowStandardHandlerAttribute |
328                                     kWindowInWindowMenuAttribute;
329     
330     SetRect( &p_vout->p_sys->wrect, left, top, right, bottom );
331     OffsetRect( &p_vout->p_sys->wrect, kWindowOffset, kWindowOffset );
332
333     CreateNewWindow( kDocumentWindowClass, windowAttr, &p_vout->p_sys->wrect, &p_vout->p_sys->p_window );
334     if ( p_vout->p_sys->p_window == nil )
335     {
336         return( 1 );
337     }
338
339     InstallStandardEventHandler(GetWindowEventTarget(p_vout->p_sys->p_window));
340     SetPort( GetWindowPort( p_vout->p_sys->p_window ) );
341     SetWindowTitleWithCFString( p_vout->p_sys->p_window, CFSTR("VLC") );
342 //    ShowWindow( p_vout->p_sys->p_window );
343     TransitionWindow( p_vout->p_sys->p_window, kWindowZoomTransitionEffect, kWindowShowTransitionAction, NULL);
344     BringToFront(  p_vout->p_sys->p_window );
345
346 {
347     short wPixDepth = (**(GetPortPixMap( GetWindowPort( p_vout->p_sys->p_window ) ))).pixelSize;
348     p_vout->i_screen_depth = wPixDepth;
349     p_vout->i_bytes_per_pixel = p_vout->i_screen_depth / 8;
350     p_vout->i_bytes_per_line   = p_vout->i_width * p_vout->i_bytes_per_pixel;
351     p_vout->p_sys->i_page_size = p_vout->i_width * p_vout->i_height * p_vout->i_bytes_per_pixel;
352
353     p_vout->i_bytes_per_line = (**(**GetWindowDevice( p_vout )).gdPMap).rowBytes & 0x3FFF ;
354
355     switch ( p_vout->i_screen_depth )
356     {
357         case 32:
358         case 24:
359             p_vout->i_red_mask =   0xff0000;
360             p_vout->i_green_mask = 0xff00;
361             p_vout->i_blue_mask =  0xff;
362             break;
363         case 16:
364         case 15:
365             p_vout->i_red_mask =   0x00007c00;
366             p_vout->i_green_mask = 0x000003e0;
367             p_vout->i_blue_mask =  0x0000001f;
368             break;
369         default:
370             break;
371     }
372
373 #if 0
374     p_vout->i_red_lshift = 0x10;
375     p_vout->i_red_rshift = 0x0;
376     p_vout->i_green_lshift = 0x8;
377     p_vout->i_green_rshift = 0x0;
378     p_vout->i_blue_lshift = 0x0;
379     p_vout->i_blue_rshift = 0x0;
380
381     p_vout->i_white_pixel = 0xffffff;
382     p_vout->i_black_pixel = 0x0;
383     p_vout->i_gray_pixel = 0x808080;
384     p_vout->i_blue_pixel = 0x32;
385 #endif
386 }
387
388     return( 0 );
389 }
390
391 /*****************************************************************************
392  * AllocBuffer: forces offscreen allocation (if different than current) in memory type specified
393  *****************************************************************************/
394 static int AllocBuffer ( vout_thread_t *p_vout, short index )
395 {
396     Rect bounds;
397     GDHandle hgdWindow = GetWindowDevice( p_vout );
398
399     switch ( p_vout->p_sys->gwLocOffscreen )
400     {
401         case kInVRAM:
402             if ( noErr == NewGWorld( &p_vout->p_sys->p_gw[index], p_vout->i_screen_depth, 
403                 GetPortBounds( GetWindowPort( p_vout->p_sys->p_window ), &bounds ), NULL, 
404                 hgdWindow, noNewDevice | useDistantHdwrMem ) )          
405             {
406                 intf_ErrMsg( "Allocate off screen image in VRAM" );
407                 break;
408             }
409             intf_ErrMsg( "Unable to allocate off screen image in VRAM, trying next best AGP" );
410             p_vout->p_sys->gwLocOffscreen = kInAGP;
411         case kInAGP:
412             if (noErr == NewGWorld( &p_vout->p_sys->p_gw[index], p_vout->i_screen_depth, 
413                 GetPortBounds( GetWindowPort( p_vout->p_sys->p_window ), &bounds ), NULL, 
414                 hgdWindow, noNewDevice | useLocalHdwrMem ) )
415             {
416                 intf_ErrMsg( "Allocate off screen image in AGP" );
417                 break;
418             }
419             intf_ErrMsg( "Unable to allocate off screen image in AGP, trying next best System" );
420             p_vout->p_sys->gwLocOffscreen = kInSystem;
421         case kInSystem:
422         default:
423             if ( noErr == NewGWorld( &p_vout->p_sys->p_gw[index], p_vout->i_screen_depth, 
424                 GetPortBounds( GetWindowPort( p_vout->p_sys->p_window ), &bounds ), NULL, 
425                 hgdWindow, noNewDevice | keepLocal) )
426             {
427                 intf_ErrMsg( "Allocate off screen image in System" );
428                 break;
429             }
430             intf_ErrMsg( "Unable to allocate off screen image in System, no options left - failing" );
431             p_vout->p_sys->gwLocOffscreen = kNoWhere;
432             return( 1 ); // nothing was allocated
433     } 
434     return( 0 );
435 }
436
437 /*****************************************************************************
438  * vout_Init: initialize video thread output method
439  *****************************************************************************/
440 static int vout_Init( vout_thread_t *p_vout )
441 {
442     //intf_ErrMsg( "vout_Init()" );
443     return( 0 );
444 }
445
446 /*****************************************************************************
447  * vout_End: terminate video thread output method
448  *****************************************************************************/
449 static void vout_End( vout_thread_t *p_vout )
450 {
451     //intf_ErrMsg( "vout_End()" );
452     ;
453 }
454
455 /*****************************************************************************
456  * vout_Destroy: destroy video thread output method
457  *****************************************************************************/
458 static void vout_Destroy( vout_thread_t *p_vout )
459 {
460     //intf_ErrMsg( "vout_Destroy()" );
461
462 //FIXME KLUDGE to lock pixels
463 #if 1
464 {
465     PixMapHandle hPixmap0, hPixmap1;
466     hPixmap0 = GetGWorldPixMap( p_vout->p_sys->p_gw[0] );
467     hPixmap1 = GetGWorldPixMap( p_vout->p_sys->p_gw[1] );
468     UnlockPixels(hPixmap0);
469     UnlockPixels(hPixmap1);
470 }
471 #endif
472
473 #if 1
474     if ( p_vout->p_sys->p_gw[0] )
475     {
476         DisposeGWorld( p_vout->p_sys->p_gw[0] );
477     }
478     if ( p_vout->p_sys->p_gw[1] )
479     {
480         DisposeGWorld( p_vout->p_sys->p_gw[1] );
481     }
482     if ( p_vout->p_sys->p_window )
483     {
484         DisposeWindow( p_vout->p_sys->p_window );
485     }
486 #endif
487     free( p_vout->p_sys->p_video );
488     free( p_vout->p_sys );
489 }
490
491 /*****************************************************************************
492  * vout_Manage: handle events
493  *****************************************************************************
494  * This function should be called regularly by video output thread. It manages
495  * console events. It returns a non null value on error.
496  *****************************************************************************/
497 static int vout_Manage( vout_thread_t *p_vout )
498 {
499 //    intf_ErrMsg( "vout_Manage()" );
500     return( 0 );
501 }
502
503 /*****************************************************************************
504  * vout_Display: displays previously rendered output
505  *****************************************************************************
506  * This function send the currently rendered image to image, waits until
507  * it is displayed and switch the two rendering buffers, preparing next frame.
508  *****************************************************************************/
509 static void vout_Display( vout_thread_t *p_vout )
510 {
511 //    intf_ErrMsg( "vout_Display()" );
512
513     BlitToWindow ( p_vout, p_vout->i_buffer_index );
514 }
515
516
517 /*****************************************************************************
518  * flushQD: flushes buffered window area
519   *****************************************************************************/
520 void flushQD( vout_thread_t *p_vout )
521 {
522     CGrafPtr thePort;
523
524     //intf_ErrMsg( "flushQD()" );
525     
526     thePort = GetWindowPort( p_vout->p_sys->p_window );
527     
528     /* flush the entire port */
529     if (QDIsPortBuffered(thePort))
530         QDFlushPortBuffer(thePort, NULL);
531
532 #if 0
533     /* flush part of the port */
534     if (QDIsPortBuffered(thePort)) {
535         RgnHandle theRgn;
536         theRgn = NewRgn();
537             /* local port coordinates */
538         SetRectRgn(theRgn, 10, 10, 100, 30); 
539         QDFlushPortBuffer(thePort, theRgn);
540         DisposeRgn(theRgn);
541     }
542 #endif
543
544 }
545
546 /*****************************************************************************
547  * BlitToWindow: checks offscreen and blits it to the front
548   *****************************************************************************/
549
550 void BlitToWindow( vout_thread_t *p_vout, short index )
551 {
552     Rect rectDest, rectSource;
553     GrafPtr pCGrafSave, windowPort = GetWindowPort( p_vout->p_sys->p_window );
554
555     //intf_ErrMsg( "BlitToWindow() for %d", index );
556
557     GetPortBounds( p_vout->p_sys->p_gw[index], &rectSource );
558     GetPortBounds( windowPort, &rectDest );
559     
560     GetPort ( &pCGrafSave );
561     SetPortWindowPort( p_vout->p_sys->p_window );
562 //FIXME have global lock - kinda bad but oh well 
563 //    if ( LockPixels( GetGWorldPixMap( p_vout->p_sys->p_gw[index] ) ) )
564 //    {
565         CopyBits( GetPortBitMapForCopyBits( p_vout->p_sys->p_gw[index] ), 
566                     GetPortBitMapForCopyBits( GetWindowPort( p_vout->p_sys->p_window ) ), 
567                     &rectSource, &rectDest, srcCopy, NULL);
568 //        UnlockPixels( GetGWorldPixMap( p_vout->p_sys->p_gw[index] ) );
569         //flushQD( p_vout );
570 //    }
571     SetPort ( pCGrafSave );
572 }
573
574
575 /*****************************************************************************
576  * GetWindowDevice: returns GDHandle that window resides on (most of it anyway)
577  *****************************************************************************/
578 GDHandle GetWindowDevice( vout_thread_t *p_vout )
579 {
580     GrafPtr pgpSave;
581     Rect rectWind, rectSect;
582     long greatestArea, sectArea;
583     GDHandle hgdNthDevice, hgdZoomOnThisDevice = NULL;
584     
585     //intf_ErrMsg( "GetWindowDevice()" );
586
587     GetPort( &pgpSave );
588     SetPortWindowPort( p_vout->p_sys->p_window );
589     GetPortBounds( GetWindowPort( p_vout->p_sys->p_window ), &rectWind );
590     LocalToGlobal( ( Point* ) &rectWind.top );
591     LocalToGlobal( ( Point* ) &rectWind.bottom );
592     hgdNthDevice = GetDeviceList();
593     greatestArea = 0;
594     // check window against all gdRects in gDevice list and remember 
595     //  which gdRect contains largest area of window}
596     while ( hgdNthDevice )
597     {
598         if ( TestDeviceAttribute( hgdNthDevice, screenDevice ) )
599         {
600             if ( TestDeviceAttribute( hgdNthDevice, screenActive ) )
601             {
602                 // The SectRect routine calculates the intersection 
603                 //  of the window rectangle and this gDevice 
604                 //  rectangle and returns TRUE if the rectangles intersect, 
605                 //  FALSE if they don't.
606                 SectRect( &rectWind, &( **hgdNthDevice ).gdRect, &rectSect );
607                 // determine which screen holds greatest window area
608                 //  first, calculate area of rectangle on current device
609                 sectArea = ( long )( rectSect.right - rectSect.left ) * ( rectSect.bottom - rectSect.top );
610                 if ( sectArea > greatestArea )
611                 {
612                     greatestArea = sectArea;    // set greatest area so far
613                     hgdZoomOnThisDevice = hgdNthDevice; // set zoom device
614                 }
615                 hgdNthDevice = GetNextDevice( hgdNthDevice );
616             }
617         }
618     }   // of WHILE
619     SetPort( pgpSave );
620     return hgdZoomOnThisDevice;
621 }
622
623 /*****************************************************************************
624  * FillOffScreen: fills offscreen buffer with random bright color
625  *****************************************************************************/
626
627 void FillOffscreen( vout_thread_t *p_vout, short index )
628 {
629     static RGBColor rgbColorOld;
630     GDHandle hGDSave;
631     CGrafPtr pCGrafSave;
632     Rect rectSource;
633     RGBColor rgbColor;
634     
635     //intf_ErrMsg( "FillOffscreen" );
636
637     GetPortBounds( p_vout->p_sys->p_gw[index], &rectSource );
638     
639     do 
640         rgbColor.red = ( Random () + 32767) / 2 + 32767;
641     while ( abs ( rgbColor.red - rgbColorOld.red ) <  3000 );   
642     do 
643         rgbColor.green = (Random () + 32767) / 2 + 32767;
644     while ( abs ( rgbColor.green - rgbColorOld.green ) <  3000);
645     do 
646         rgbColor.blue = (Random () + 32767) / 2 + 32767;
647     while ( abs ( rgbColor.blue - rgbColorOld.blue ) <  3000);
648     
649     rgbColorOld = rgbColor;
650
651     GetGWorld( &pCGrafSave, &hGDSave );
652     SetGWorld( p_vout->p_sys->p_gw[index], NULL );
653 //FIXME have global lock - kinda bad but oh well 
654 //    if ( LockPixels( GetGWorldPixMap( p_vout->p_sys->p_gw[index] ) ) )
655 //    {
656         // draw some background
657         EraseRect( &rectSource );
658         RGBForeColor( &rgbColor );
659         PaintRect( &rectSource );
660 //        UnlockPixels( GetGWorldPixMap( p_vout->p_sys->p_gw[index] ) );
661 //    }
662     SetGWorld( pCGrafSave, hGDSave );
663 }