* added mouse management in the BeOS video output.
[vlc.git] / modules / gui / beos / VideoOutput.cpp
1 /*****************************************************************************
2  * vout_beos.cpp: beos video output display method
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: VideoOutput.cpp,v 1.7 2002/12/03 02:00:37 titer Exp $
6  *
7  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Tony Castley <tcastley@mail.powerup.com.au>
10  *          Richard Shepherd <richard@rshepherd.demon.co.uk>
11  *          Stephan Aßmus <stippi@yellowbites.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <errno.h>                                                 /* ENOMEM */
32 #include <stdlib.h>                                                /* free() */
33 #include <stdio.h>
34 #include <string.h>                                            /* strerror() */
35
36 #include <Application.h>
37 #include <BitmapStream.h>
38 #include <Bitmap.h>
39 #include <DirectWindow.h>
40 #include <File.h>
41 #include <InterfaceKit.h>
42 #include <NodeInfo.h>
43 #include <String.h>
44 #include <TranslatorRoster.h>
45
46 /* VLC headers */
47 #include <vlc/vlc.h>
48 #include <vlc/intf.h>
49 #include <vlc/vout.h>
50
51 #include "VideoWindow.h"
52 #include "DrawingTidbits.h"
53 #include "MsgVals.h"
54
55 /*****************************************************************************
56  * vout_sys_t: BeOS video output method descriptor
57  *****************************************************************************
58  * This structure is part of the video output thread descriptor.
59  * It describes the BeOS specific properties of an output thread.
60  *****************************************************************************/
61 struct vout_sys_t
62 {
63     VideoWindow *  p_window;
64
65     s32 i_width;
66     s32 i_height;
67
68 //    u8 *pp_buffer[3];
69     u32 source_chroma;
70     int i_index;
71
72 };
73
74 #define MOUSE_IDLE_TIMEOUT 2000000      // two seconds
75 #define MIN_AUTO_VSYNC_REFRESH 61       // Hz
76 #define DEFAULT_SCREEN_SHOT_FORMAT 'PNG '
77 #define DEFAULT_SCREEN_SHOT_PATH "/boot/home/vlc screenshot"
78
79 /*****************************************************************************
80  * beos_GetAppWindow : retrieve a BWindow pointer from the window name
81  *****************************************************************************/
82 BWindow*
83 beos_GetAppWindow(char *name)
84 {
85     int32       index;
86     BWindow     *window;
87     
88     for (index = 0 ; ; index++)
89     {
90         window = be_app->WindowAt(index);
91         if (window == NULL)
92             break;
93         if (window->LockWithTimeout(20000) == B_OK)
94         {
95             if (strcmp(window->Name(), name) == 0)
96             {
97                 window->Unlock();
98                 break;
99             }
100             window->Unlock();
101         }
102     }
103     return window; 
104 }
105
106 /*****************************************************************************
107  * get_interface_window
108  *****************************************************************************/
109 BWindow*
110 get_interface_window()
111 {
112         return beos_GetAppWindow(VOUT_TITLE);
113 }
114
115 class BackgroundView : public BView
116 {
117  public:
118                                                         BackgroundView(BRect frame, VLCView* view)
119                                                         : BView(frame, "background",
120                                                                         B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
121                                                           fVideoView(view)
122                                                         {
123                                                                 SetViewColor(kBlack);
124                                                         }
125         virtual                                 ~BackgroundView() {}
126
127         virtual void                    MouseDown(BPoint where)
128                                                         {
129                                                                 // convert coordinates
130                                                                 where = fVideoView->ConvertFromParent(where);
131                                                                 // let him handle it
132                                                                 fVideoView->MouseDown(where);
133                                                         }
134         virtual void                    MouseMoved(BPoint where, uint32 transit,
135                                                                            const BMessage* dragMessage)
136                                                         {
137                                                                 // convert coordinates
138                                                                 where = fVideoView->ConvertFromParent(where);
139                                                                 // let him handle it
140                                                                 fVideoView->MouseMoved(where, transit, dragMessage);
141                                                                 // notice: It might look like transit should be
142                                                                 // B_OUTSIDE_VIEW regardless, but leave it like this,
143                                                                 // otherwise, unwanted things will happen!
144                                                         }
145
146  private:
147         VLCView*                                fVideoView;
148 };
149
150 /*****************************************************************************
151  * VideoWindow constructor and destructor
152  *****************************************************************************/
153 VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
154                          vout_thread_t *p_videoout)
155         : BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
156           i_width(frame.IntegerWidth()),
157           i_height(frame.IntegerHeight()),
158           is_zoomed(false),
159           vsync(false),
160           i_buffer(0),
161           teardownwindow(false),
162           fTrueWidth(v_width),
163           fTrueHeight(v_height),
164           fCorrectAspect(true),
165           fCachedFeel(B_NORMAL_WINDOW_FEEL),
166           fInterfaceShowing(false),
167           fInitStatus(B_ERROR)
168 {
169     p_vout = p_videoout;
170     
171     // create the view to do the display
172     view = new VLCView( Bounds(), p_vout );
173
174         // create background view
175     BView *mainView =  new BackgroundView( Bounds(), view );
176     AddChild(mainView);
177     mainView->AddChild(view);
178
179         // figure out if we should use vertical sync by default
180         BScreen screen(this);
181         if (screen.IsValid())
182         {
183                 display_mode mode; 
184                 screen.GetMode(&mode); 
185                 float refresh = (mode.timing.pixel_clock * 1000)
186                                                 / ((mode.timing.h_total)* (mode.timing.v_total)); 
187                 vsync = (refresh < MIN_AUTO_VSYNC_REFRESH);
188         }
189
190         // allocate bitmap buffers
191         for (int32 i = 0; i < 3; i++)
192                 bitmap[i] = NULL;
193         fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
194
195         // make sure we layout the view correctly
196     FrameResized(i_width, i_height);
197
198     if (fInitStatus >= B_OK && mode == OVERLAY)
199     {
200        overlay_restrictions r;
201
202        bitmap[1]->GetOverlayRestrictions(&r);
203        SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
204                      (i_height * r.min_height_scale), i_height * r.max_height_scale);
205     }
206     
207     if( config_GetInt( p_vout, "fullscreen" ) )
208     {
209         BWindow::Zoom();;
210     }
211 }
212
213 VideoWindow::~VideoWindow()
214 {
215     int32 result;
216
217     teardownwindow = true;
218     wait_for_thread(fDrawThreadID, &result);
219     _FreeBuffers();
220 }
221
222 /*****************************************************************************
223  * VideoWindow::MessageReceived
224  *****************************************************************************/
225 void
226 VideoWindow::MessageReceived( BMessage *p_message )
227 {
228         switch( p_message->what )
229         {
230                 case TOGGLE_FULL_SCREEN:
231                         BWindow::Zoom();
232                         break;
233                 case RESIZE_50:
234                 case RESIZE_100:
235                 case RESIZE_200:
236                         if (is_zoomed)
237                                 BWindow::Zoom();
238                         _SetVideoSize(p_message->what);
239                         break;
240                 case VERT_SYNC:
241                         vsync = !vsync;
242                         break;
243                 case WINDOW_FEEL:
244                         {
245                                 window_feel winFeel;
246                                 if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
247                                 {
248                                         SetFeel(winFeel);
249                                         fCachedFeel = winFeel;
250                                 }
251                         }
252                         break;
253                 case ASPECT_CORRECT:
254                         SetCorrectAspectRatio(!fCorrectAspect);
255                         break;
256                 case SCREEN_SHOT:
257                         // save a screen shot
258                         if ( BBitmap* current = bitmap[i_buffer] )
259                         {
260 // the following line might be tempting, but does not work for some overlay bitmaps!!!
261 //                              BBitmap* temp = new BBitmap( current );
262 // so we clone the bitmap ourselves
263 // however, we need to take care of potentially different padding!
264 // memcpy() is slow when reading from grafix memory, but what the heck...
265                                 BBitmap* temp = new BBitmap( current->Bounds(), current->ColorSpace() );
266                                 if ( temp && temp->IsValid() )
267                                 {
268                                         int32 height = (int32)current->Bounds().Height();
269                                         uint8* dst = (uint8*)temp->Bits();
270                                         uint8* src = (uint8*)current->Bits();
271                                         int32 dstBpr = temp->BytesPerRow();
272                                         int32 srcBpr = current->BytesPerRow();
273                                         int32 validBytes = dstBpr > srcBpr ? srcBpr : dstBpr;
274                                         for ( int32 y = 0; y < height; y++ )
275                                         {
276                                                 memcpy( dst, src, validBytes );
277                                                 dst += dstBpr;
278                                                 src += srcBpr;
279                                         }
280                                         _SaveScreenShot( temp,
281                                                                          strdup( DEFAULT_SCREEN_SHOT_PATH ),
282                                                                          DEFAULT_SCREEN_SHOT_FORMAT );
283                                 }
284                                 else
285                                 {
286                                         delete temp;
287                                         fprintf( stderr, "error copying bitmaps\n" );
288                                 }
289                         }
290                         break;
291                 default:
292                         BWindow::MessageReceived( p_message );
293                         break;
294         }
295 }
296
297 /*****************************************************************************
298  * VideoWindow::Zoom
299  *****************************************************************************/
300 void
301 VideoWindow::Zoom(BPoint origin, float width, float height )
302 {
303         if(is_zoomed)
304         {
305                 MoveTo(winSize.left, winSize.top);
306                 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
307                 be_app->ShowCursor();
308                 fInterfaceShowing = true;
309         }
310         else
311         {
312                 BScreen screen(this);
313                 BRect rect = screen.Frame();
314                 Activate();
315                 MoveTo(0.0, 0.0);
316                 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
317                 be_app->ObscureCursor();
318                 fInterfaceShowing = false;
319         }
320         is_zoomed = !is_zoomed;
321 }
322
323 /*****************************************************************************
324  * VideoWindow::FrameMoved
325  *****************************************************************************/
326 void
327 VideoWindow::FrameMoved(BPoint origin) 
328 {
329         if (is_zoomed) return ;
330     winSize = Frame();
331 }
332
333 /*****************************************************************************
334  * VideoWindow::FrameResized
335  *****************************************************************************/
336 void
337 VideoWindow::FrameResized( float width, float height )
338 {
339         int32 useWidth = fCorrectAspect ? i_width : fTrueWidth;
340         int32 useHeight = fCorrectAspect ? i_height : fTrueHeight;
341     float out_width, out_height;
342     float out_left, out_top;
343     float width_scale = width / useWidth;
344     float height_scale = height / useHeight;
345
346     if (width_scale <= height_scale)
347     {
348         out_width = (useWidth * width_scale);
349         out_height = (useHeight * width_scale);
350         out_left = 0; 
351         out_top = (height - out_height) / 2;
352     }
353     else   /* if the height is proportionally smaller */
354     {
355         out_width = (useWidth * height_scale);
356         out_height = (useHeight * height_scale);
357         out_top = 0;
358         out_left = (width - out_width) / 2;
359     }
360     view->MoveTo(out_left,out_top);
361     view->ResizeTo(out_width, out_height);
362
363         if (!is_zoomed)
364         winSize = Frame();
365 }
366
367 /*****************************************************************************
368  * VideoWindow::ScreenChanged
369  *****************************************************************************/
370 void
371 VideoWindow::ScreenChanged(BRect frame, color_space format)
372 {
373         BScreen screen(this);
374         display_mode mode; 
375         screen.GetMode(&mode); 
376         float refresh = (mode.timing.pixel_clock * 1000)
377                                         / ((mode.timing.h_total) * (mode.timing.v_total)); 
378     if (refresh < MIN_AUTO_VSYNC_REFRESH) 
379         vsync = true; 
380 }
381
382 /*****************************************************************************
383  * VideoWindow::Activate
384  *****************************************************************************/
385 void
386 VideoWindow::WindowActivated(bool active)
387 {
388 }
389
390 /*****************************************************************************
391  * VideoWindow::drawBuffer
392  *****************************************************************************/
393 void
394 VideoWindow::drawBuffer(int bufferIndex)
395 {
396     i_buffer = bufferIndex;
397
398     // sync to the screen if required
399     if (vsync)
400     {
401         BScreen screen(this);
402         screen.WaitForRetrace(22000);
403     }
404     if (fInitStatus >= B_OK && LockLooper())
405     {
406        // switch the overlay bitmap
407        if (mode == OVERLAY)
408        {
409           rgb_color key;
410           view->SetViewOverlay(bitmap[i_buffer], 
411                             bitmap[i_buffer]->Bounds() ,
412                             view->Bounds(),
413                             &key, B_FOLLOW_ALL,
414                                                         B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
415                                     B_OVERLAY_TRANSFER_CHANNEL);
416                    view->SetViewColor(key);
417            }
418        else
419        {
420          // switch the bitmap
421          view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
422        }
423        UnlockLooper();
424     }
425 }
426
427 /*****************************************************************************
428  * VideoWindow::SetInterfaceShowing
429  *****************************************************************************/
430 void
431 VideoWindow::ToggleInterfaceShowing()
432 {
433         SetInterfaceShowing(!fInterfaceShowing);
434 }
435
436 /*****************************************************************************
437  * VideoWindow::SetInterfaceShowing
438  *****************************************************************************/
439 void
440 VideoWindow::SetInterfaceShowing(bool showIt)
441 {
442         BWindow* window = get_interface_window();
443         if (window)
444         {
445                 if (showIt)
446                 {
447                         if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
448                                 SetFeel(B_NORMAL_WINDOW_FEEL);
449                         window->Activate(true);
450                         SendBehind(window);
451                 }
452                 else
453                 {
454                         SetFeel(fCachedFeel);
455                         Activate(true);
456                         window->SendBehind(this);
457                 }
458                 fInterfaceShowing = showIt;
459         }
460 }
461
462 /*****************************************************************************
463  * VideoWindow::SetCorrectAspectRatio
464  *****************************************************************************/
465 void
466 VideoWindow::SetCorrectAspectRatio(bool doIt)
467 {
468         if (fCorrectAspect != doIt)
469         {
470                 fCorrectAspect = doIt;
471                 FrameResized(Bounds().Width(), Bounds().Height());
472         }
473 }
474
475 /*****************************************************************************
476  * VideoWindow::_AllocateBuffers
477  *****************************************************************************/
478 status_t
479 VideoWindow::_AllocateBuffers(int width, int height, int* mode)
480 {
481         // clear any old buffers
482         _FreeBuffers();
483         // set default mode
484         *mode = BITMAP;
485
486         BRect bitmapFrame( 0, 0, width, height );
487         // read from config, if we are supposed to use overlay at all
488     int noOverlay = !config_GetInt( p_vout, "overlay" );
489         // test for overlay capability
490     for (int i = 0; i < COLOR_COUNT; i++)
491     {
492         if (noOverlay) break;
493         bitmap[0] = new BBitmap ( bitmapFrame, 
494                                   B_BITMAP_WILL_OVERLAY |
495                                   B_BITMAP_RESERVE_OVERLAY_CHANNEL,
496                                   colspace[i].colspace);
497
498         if(bitmap[0] && bitmap[0]->InitCheck() == B_OK) 
499         {
500             colspace_index = i;
501
502             bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
503                                      colspace[colspace_index].colspace);
504             bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
505                                      colspace[colspace_index].colspace);
506             if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
507             {
508                *mode = OVERLAY;
509                rgb_color key;
510                view->SetViewOverlay(bitmap[0], 
511                                     bitmap[0]->Bounds() ,
512                                     view->Bounds(),
513                                     &key, B_FOLLOW_ALL,
514                                             B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
515                        view->SetViewColor(key);
516                SetTitle(VOUT_TITLE " (Overlay)");
517                break;
518             }
519             else
520             {
521                _FreeBuffers();
522                *mode = BITMAP; // might want to try again with normal bitmaps
523             }
524         }
525         else
526             delete bitmap[0];
527         }
528
529     if (*mode == BITMAP)
530         {
531         // fallback to RGB
532         colspace_index = DEFAULT_COL;   // B_RGB16
533 // FIXME: an error in the YUV->RGB32 module prevents this from being used!
534 /*        BScreen screen( B_MAIN_SCREEN_ID );
535         if ( screen.ColorSpace() == B_RGB32 )
536                 colspace_index = 3;                     // B_RGB32 (faster on 32 bit screen)*/
537         SetTitle( VOUT_TITLE " (Bitmap)" );
538         bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
539         bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
540         bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
541     }
542     // see if everything went well
543     status_t status = B_ERROR;
544     for (int32 i = 0; i < 3; i++)
545     {
546         if (bitmap[i])
547                 status = bitmap[i]->InitCheck();
548                 if (status < B_OK)
549                         break;
550     }
551     if (status >= B_OK)
552     {
553             // clear bitmaps to black
554             for (int32 i = 0; i < 3; i++)
555                 _BlankBitmap(bitmap[i]);
556     }
557     return status;
558 }
559
560 /*****************************************************************************
561  * VideoWindow::_FreeBuffers
562  *****************************************************************************/
563 void
564 VideoWindow::_FreeBuffers()
565 {
566         delete bitmap[0];
567         bitmap[0] = NULL;
568         delete bitmap[1];
569         bitmap[1] = NULL;
570         delete bitmap[2];
571         bitmap[2] = NULL;
572         fInitStatus = B_ERROR;
573 }
574
575 /*****************************************************************************
576  * VideoWindow::_BlankBitmap
577  *****************************************************************************/
578 void
579 VideoWindow::_BlankBitmap(BBitmap* bitmap) const
580 {
581         // no error checking (we do that earlier on and since it's a private function...
582
583         // YCbCr: 
584         // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
585
586         // YUV: 
587         // Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
588
589         // we only handle weird colorspaces with special care
590         switch (bitmap->ColorSpace()) {
591                 case B_YCbCr422: {
592                         // Y0[7:0]  Cb0[7:0]  Y1[7:0]  Cr0[7:0]  Y2[7:0]  Cb2[7:0]  Y3[7:0]  Cr2[7:0]
593                         int32 height = bitmap->Bounds().IntegerHeight() + 1;
594                         uint8* bits = (uint8*)bitmap->Bits();
595                         int32 bpr = bitmap->BytesPerRow();
596                         for (int32 y = 0; y < height; y++) {
597                                 // handle 2 bytes at a time
598                                 for (int32 i = 0; i < bpr; i += 2) {
599                                         // offset into line
600                                         bits[i] = 16;
601                                         bits[i + 1] = 128;
602                                 }
603                                 // next line
604                                 bits += bpr;
605                         }
606                         break;
607                 }
608                 case B_YCbCr420: {
609 // TODO: untested!!
610                         // Non-interlaced only, Cb0  Y0  Y1  Cb2 Y2  Y3  on even scan lines ...
611                         // Cr0  Y0  Y1  Cr2 Y2  Y3  on odd scan lines
612                         int32 height = bitmap->Bounds().IntegerHeight() + 1;
613                         uint8* bits = (uint8*)bitmap->Bits();
614                         int32 bpr = bitmap->BytesPerRow();
615                         for (int32 y = 0; y < height; y += 1) {
616                                 // handle 3 bytes at a time
617                                 for (int32 i = 0; i < bpr; i += 3) {
618                                         // offset into line
619                                         bits[i] = 128;
620                                         bits[i + 1] = 16;
621                                         bits[i + 2] = 16;
622                                 }
623                                 // next line
624                                 bits += bpr;
625                         }
626                         break;
627                 }
628                 case B_YUV422: {
629 // TODO: untested!!
630                         // U0[7:0]  Y0[7:0]   V0[7:0]  Y1[7:0]  U2[7:0]  Y2[7:0]   V2[7:0]  Y3[7:0]
631                         int32 height = bitmap->Bounds().IntegerHeight() + 1;
632                         uint8* bits = (uint8*)bitmap->Bits();
633                         int32 bpr = bitmap->BytesPerRow();
634                         for (int32 y = 0; y < height; y += 1) {
635                                 // handle 2 bytes at a time
636                                 for (int32 i = 0; i < bpr; i += 2) {
637                                         // offset into line
638                                         bits[i] = 128;
639                                         bits[i + 1] = 0;
640                                 }
641                                 // next line
642                                 bits += bpr;
643                         }
644                         break;
645                 }
646                 default:
647                         memset(bitmap->Bits(), 0, bitmap->BitsLength());
648                         break;
649         }
650 }
651
652 /*****************************************************************************
653  * VideoWindow::_SetVideoSize
654  *****************************************************************************/
655 void
656 VideoWindow::_SetVideoSize(uint32 mode)
657 {
658         // let size depend on aspect correction
659         int32 width = fCorrectAspect ? i_width : fTrueWidth;
660         int32 height = fCorrectAspect ? i_height : fTrueHeight;
661         switch (mode)
662         {
663                 case RESIZE_50:
664                         width /= 2;
665                         height /= 2;
666                         break;
667                 case RESIZE_200:
668                         width *= 2;
669                         height *= 2;
670                         break;
671                 case RESIZE_100:
672                 default:
673                 break;
674         }
675         ResizeTo(width, height);
676         is_zoomed = false;
677 }
678
679 /*****************************************************************************
680  * VideoWindow::_SaveScreenShot
681  *****************************************************************************/
682 void
683 VideoWindow::_SaveScreenShot( BBitmap* bitmap, char* path,
684                                                   uint32 translatorID ) const
685 {
686         // make the info object from the parameters
687         screen_shot_info* info = new screen_shot_info;
688         info->bitmap = bitmap;
689         info->path = path;
690         info->translatorID = translatorID;
691         info->width = fCorrectAspect ? i_width : fTrueWidth;
692         info->height = fCorrectAspect ? i_height : fTrueHeight;
693         // spawn a new thread to take care of the actual saving to disk
694         thread_id thread = spawn_thread( _save_screen_shot,
695                                                                          "screen shot saver",
696                                                                          B_LOW_PRIORITY, (void*)info );
697         // start thread or do the job ourself if something went wrong
698         if ( thread < B_OK || resume_thread( thread ) < B_OK )
699                 _save_screen_shot( (void*)info );
700 }
701
702 /*****************************************************************************
703  * VideoWindow::_save_screen_shot
704  *****************************************************************************/
705 int32
706 VideoWindow::_save_screen_shot( void* cookie )
707 {
708         screen_shot_info* info = (screen_shot_info*)cookie;
709         if ( info && info->bitmap && info->bitmap->IsValid() && info->path )
710         {
711                 // try to be as quick as possible creating the file (the user might have
712                 // taken the next screen shot already!)
713                 // make sure we have a unique name for the screen shot
714                 BString path( info->path );
715                 BEntry entry( path.String() );
716                 int32 appendedNumber = 0;
717                 if ( entry.Exists() && !entry.IsSymLink() )
718                 {
719                         // we would clobber an existing entry
720                         bool foundUniqueName = false;
721                         appendedNumber = 1;
722                         while ( !foundUniqueName ) {
723                                 BString newName( info->path );
724                                 newName << " " << appendedNumber;
725                                 BEntry possiblyClobberedEntry( newName.String() );
726                                 if ( possiblyClobberedEntry.Exists()
727                                         && !possiblyClobberedEntry.IsSymLink() )
728                                         appendedNumber++;
729                                 else
730                                         foundUniqueName = true;
731                         }
732                 }
733                 if ( appendedNumber > 0 )
734                         path << " " << appendedNumber;
735                 // there is still a slight chance to clobber an existing
736                 // file (if it was created in the "meantime"), but we take it...
737                 BFile outFile( path.String(),
738                                            B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE );
739
740                 // make colorspace converted copy of bitmap
741                 BBitmap* converted = new BBitmap( BRect( 0.0, 0.0, info->width, info->height ),
742                                                                                   B_RGB32 );
743 //              if ( converted->IsValid() )
744 //                      memset( converted->Bits(), 0, converted->BitsLength() );
745                 status_t status = convert_bitmap( info->bitmap, converted );
746                 if ( status == B_OK )
747                 {
748                         BTranslatorRoster* roster = BTranslatorRoster::Default();
749                         uint32 imageFormat = 0;
750                         translator_id translator = 0;
751                         bool found = false;
752
753                         // find suitable translator
754                         translator_id* ids = NULL;
755                         int32 count = 0;
756                 
757                         status = roster->GetAllTranslators( &ids, &count );
758                         if ( status >= B_OK )
759                         {
760                                 for ( int tix = 0; tix < count; tix++ )
761                                 { 
762                                         const translation_format *formats = NULL; 
763                                         int32 num_formats = 0; 
764                                         bool ok = false; 
765                                         status = roster->GetInputFormats( ids[tix],
766                                                                                                           &formats, &num_formats );
767                                         if (status >= B_OK)
768                                         {
769                                                 for ( int iix = 0; iix < num_formats; iix++ )
770                                                 { 
771                                                         if ( formats[iix].type == B_TRANSLATOR_BITMAP )
772                                                         { 
773                                                                 ok = true; 
774                                                                 break; 
775                                                         }
776                                                 }
777                                         }
778                                         if ( !ok )
779                                                 continue; 
780                                         status = roster->GetOutputFormats( ids[tix],
781                                                                                                            &formats, &num_formats); 
782                                         if ( status >= B_OK )
783                                         {
784                                                 for ( int32 oix = 0; oix < num_formats; oix++ )
785                                                 {
786                                                         if ( formats[oix].type != B_TRANSLATOR_BITMAP )
787                                                         {
788                                                                 if ( formats[oix].type == info->translatorID )
789                                                                 {
790                                                                         found = true;
791                                                                         imageFormat = formats[oix].type;
792                                                                         translator = ids[tix];
793                                                                         break;
794                                                                 }
795                                                         }
796                                                 }
797                                         }
798                                 }
799                         }
800                         delete[] ids;
801                         if ( found )
802                         {
803                                 // make bitmap stream
804                                 BBitmapStream outStream( converted );
805
806                                 status = outFile.InitCheck();
807                                 if (status == B_OK) {
808                                         status = roster->Translate( &outStream, NULL, NULL,
809                                                                                                 &outFile, imageFormat );
810                                         if ( status == B_OK )
811                                         {
812                                                 BNodeInfo nodeInfo( &outFile );
813                                                 if ( nodeInfo.InitCheck() == B_OK )
814                                                 {
815                                                         translation_format* formats; 
816                                                         int32 count;
817                                                         status = roster->GetOutputFormats( translator,
818                                                                                                                            (const translation_format **) &formats,
819                                                                                                                            &count);
820                                                         if ( status >= B_OK )
821                                                         {
822                                                                 const char * mime = NULL; 
823                                                                 for ( int ix = 0; ix < count; ix++ ) {
824                                                                         if ( formats[ix].type == imageFormat ) {
825                                                                                 mime = formats[ix].MIME;
826                                                                                 break;
827                                                                         }
828                                                                 } 
829                                                                 if ( mime )
830                                                                         nodeInfo.SetType( mime );
831                                                         }
832                                                 }
833                                         } else {
834                                                 fprintf( stderr, "  failed to write bitmap: %s\n",
835                                                                  strerror( status ) );
836                                         }
837                                 } else {
838                                         fprintf( stderr, "  failed to create output file: %s\n",
839                                                          strerror( status ) );
840                                 }
841                                 outStream.DetachBitmap( &converted );
842                                 outFile.Unset();
843                         }
844                         else
845                                 fprintf( stderr, "  failed to find translator\n");
846                 }
847                 else
848                                 fprintf( stderr, "  failed to convert colorspace: %s\n",
849                                                  strerror( status ) );
850                 delete converted;
851         }
852         if ( info )
853         {
854                 delete info->bitmap;
855                 delete[] info->path;
856         }
857         delete info;
858         return B_OK;
859 }
860
861
862 /*****************************************************************************
863  * VLCView::VLCView
864  *****************************************************************************/
865 VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
866         : BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
867           fLastMouseMovedTime(system_time()),
868           fCursorHidden(false),
869           fCursorInside(false),
870           fIgnoreDoubleClick(false)
871 {
872     p_vout = p_vout_instance;
873     SetViewColor(B_TRANSPARENT_32_BIT);
874 }
875
876 /*****************************************************************************
877  * VLCView::~VLCView
878  *****************************************************************************/
879 VLCView::~VLCView()
880 {
881 }
882
883 /*****************************************************************************
884  * VLCVIew::AttachedToWindow
885  *****************************************************************************/
886 void
887 VLCView::AttachedToWindow()
888 {
889         // in order to get keyboard events
890         MakeFocus(true);
891         // periodically check if we want to hide the pointer
892         Window()->SetPulseRate(1000000);
893 }
894
895 /*****************************************************************************
896  * VLCVIew::MouseDown
897  *****************************************************************************/
898 void
899 VLCView::MouseDown(BPoint where)
900 {
901         VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
902         BMessage* msg = Window()->CurrentMessage();
903         msg->PrintToStream();
904         int32 clicks;
905         uint32 buttons;
906         msg->FindInt32("clicks", &clicks);
907         msg->FindInt32("buttons", (int32*)&buttons);
908
909         if (videoWindow)
910         {
911                 if (buttons & B_PRIMARY_MOUSE_BUTTON)
912                 {
913                         if (clicks == 2 && !fIgnoreDoubleClick)
914                                 Window()->Zoom();
915                         else
916                                 videoWindow->ToggleInterfaceShowing();
917                         fIgnoreDoubleClick = false;
918                 }
919             else
920             {
921                         if (buttons & B_SECONDARY_MOUSE_BUTTON) 
922                         {
923                                 // clicks will be 2 next time (if interval short enough)
924                                 // even if the first click and the second
925                                 // have not been made with the same mouse button
926                                 fIgnoreDoubleClick = true;
927                                 // launch popup menu
928                                 BPopUpMenu *menu = new BPopUpMenu("context menu");
929                                 menu->SetRadioMode(false);
930                                 // Resize to 50%
931                                 BMenuItem *halfItem = new BMenuItem("50%", new BMessage(RESIZE_50));
932                                 menu->AddItem(halfItem);
933                                 // Resize to 100%
934                                 BMenuItem *origItem = new BMenuItem("100%", new BMessage(RESIZE_100));
935                                 menu->AddItem(origItem);
936                                 // Resize to 200%
937                                 BMenuItem *doubleItem = new BMenuItem("200%", new BMessage(RESIZE_200));
938                                 menu->AddItem(doubleItem);
939                                 // Toggle FullScreen
940                                 BMenuItem *zoomItem = new BMenuItem("Fullscreen", new BMessage(TOGGLE_FULL_SCREEN));
941                                 zoomItem->SetMarked(videoWindow->is_zoomed);
942                                 menu->AddItem(zoomItem);
943         
944                                 menu->AddSeparatorItem();
945         
946                                 // Toggle vSync
947                                 BMenuItem *vsyncItem = new BMenuItem("Vertical Sync", new BMessage(VERT_SYNC));
948                                 vsyncItem->SetMarked(videoWindow->vsync);
949                                 menu->AddItem(vsyncItem);
950                                 // Correct Aspect Ratio
951                                 BMenuItem *aspectItem = new BMenuItem("Correct Aspect Ratio", new BMessage(ASPECT_CORRECT));
952                                 aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
953                                 menu->AddItem(aspectItem);
954         
955                                 menu->AddSeparatorItem();
956         
957                                 // Windwo Feel Items
958 /*                              BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
959                                 winNormFeel->AddInt32("WinFeel", (int32)B_NORMAL_WINDOW_FEEL);
960                                 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
961                                 normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
962                                 menu->AddItem(normWindItem);
963                                 
964                                 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
965                                 winFloatFeel->AddInt32("WinFeel", (int32)B_FLOATING_APP_WINDOW_FEEL);
966                                 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
967                                 onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
968                                 menu->AddItem(onTopWindItem);
969                                 
970                                 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
971                                 winAllFeel->AddInt32("WinFeel", (int32)B_FLOATING_ALL_WINDOW_FEEL);
972                                 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
973                                 allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
974                                 menu->AddItem(allSpacesWindItem);*/
975
976                                 BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
977                                 bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
978                                 window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
979                                 windowFeelMsg->AddInt32( "WinFeel", (int32)feel );
980                                 BMenuItem *windowFeelItem = new BMenuItem( "Stay On Top", windowFeelMsg );
981                                 windowFeelItem->SetMarked( onTop );
982                                 menu->AddItem( windowFeelItem );
983
984                                 menu->AddSeparatorItem();
985
986                                 BMenuItem* screenShotItem = new BMenuItem( "Take Screen Shot",
987                                                                                                                    new BMessage( SCREEN_SHOT ) );
988                                 menu->AddItem( screenShotItem );
989
990                                 menu->SetTargetForItems( this );
991                                 ConvertToScreen( &where );
992                                 menu->Go( where, true, false, true );
993                 }
994                 }
995         }
996         fLastMouseMovedTime = system_time();
997         fCursorHidden = false;
998 }
999
1000 /*****************************************************************************
1001  * VLCVIew::MouseUp
1002  *****************************************************************************/
1003 void
1004 VLCView::MouseUp( BPoint where )
1005 {
1006     vlc_value_t val;
1007     val.b_bool = VLC_TRUE;
1008     var_Set( p_vout, "mouse-clicked", val );
1009 }
1010
1011 /*****************************************************************************
1012  * VLCVIew::MouseMoved
1013  *****************************************************************************/
1014 void
1015 VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage)
1016 {
1017         fLastMouseMovedTime = system_time();
1018         fCursorHidden = false;
1019         fCursorInside = (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW);
1020         /* DVD navigation */
1021         unsigned int i_width, i_height, i_x, i_y;
1022     vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
1023                        (unsigned int)Bounds().Height(),
1024                        &i_x, &i_y, &i_width, &i_height );
1025         vlc_value_t val;
1026         val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
1027         var_Set( p_vout, "mouse-x", val );
1028         val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
1029         var_Set( p_vout, "mouse-y", val );
1030         val.b_bool = VLC_TRUE;
1031     var_Set( p_vout, "mouse-moved", val );
1032 }
1033
1034 /*****************************************************************************
1035  * VLCVIew::Pulse
1036  *****************************************************************************/
1037 void 
1038 VLCView::Pulse()
1039 {
1040         // We are getting the pulse messages no matter if the mouse is over
1041         // this view. If we are in full screen mode, we want to hide the cursor
1042         // even if it is not.
1043         if (!fCursorHidden)
1044         {
1045                 if (fCursorInside
1046                         && system_time() - fLastMouseMovedTime > MOUSE_IDLE_TIMEOUT)
1047                 {
1048                         be_app->ObscureCursor();
1049                         fCursorHidden = true;
1050                         VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1051                         // hide the interface window as well if full screen
1052                         if (videoWindow && videoWindow->is_zoomed)
1053                                 videoWindow->SetInterfaceShowing(false);
1054                 }
1055         }
1056 }
1057
1058 /*****************************************************************************
1059  * VLCVIew::KeyDown
1060  *****************************************************************************/
1061 void
1062 VLCView::KeyDown(const char *bytes, int32 numBytes)
1063 {
1064     VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1065     BWindow* interfaceWindow = get_interface_window();
1066         if (videoWindow && numBytes > 0) {
1067                 uint32 mods = modifiers();
1068                 switch (*bytes) {
1069                         case B_TAB:
1070                                 // toggle window and full screen mode
1071                                 // not passing on the tab key to the default KeyDown()
1072                                 // implementation also avoids loosing the keyboard focus
1073                                 videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1074                                 break;
1075                         case B_ESCAPE:
1076                                 // go back to window mode
1077                                 if (videoWindow->is_zoomed)
1078                                         videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1079                                 break;
1080                         case B_SPACE:
1081                                 // toggle playback
1082                                 if (interfaceWindow)
1083                                         interfaceWindow->PostMessage(PAUSE_PLAYBACK);
1084                                 break;
1085                         case B_RIGHT_ARROW:
1086                                 if (interfaceWindow)
1087                                 {
1088                                         if (mods & B_SHIFT_KEY)
1089                                                 // next title
1090                                                 interfaceWindow->PostMessage(NEXT_TITLE);
1091                                         else
1092                                                 // next chapter
1093                                                 interfaceWindow->PostMessage(NEXT_CHAPTER);
1094                                 }
1095                                 break;
1096                         case B_LEFT_ARROW:
1097                                 if (interfaceWindow)
1098                                 {
1099                                         if (mods & B_SHIFT_KEY)
1100                                                 // previous title
1101                                                 interfaceWindow->PostMessage(PREV_TITLE);
1102                                         else
1103                                                 // previous chapter
1104                                                 interfaceWindow->PostMessage(PREV_CHAPTER);
1105                                 }
1106                                 break;
1107                         case B_UP_ARROW:
1108                                 // previous file in playlist
1109                                 interfaceWindow->PostMessage(PREV_FILE);
1110                                 break;
1111                         case B_DOWN_ARROW:
1112                                 // next file in playlist
1113                                 interfaceWindow->PostMessage(NEXT_FILE);
1114                                 break;
1115                         case B_PRINT_KEY:
1116                         case 's':
1117                         case 'S':
1118                                 videoWindow->PostMessage( SCREEN_SHOT );
1119                                 break;
1120                         default:
1121                                 BView::KeyDown(bytes, numBytes);
1122                                 break;
1123                 }
1124         }
1125 }
1126
1127 /*****************************************************************************
1128  * VLCVIew::Draw
1129  *****************************************************************************/
1130 void
1131 VLCView::Draw(BRect updateRect) 
1132 {
1133         VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
1134         if ( window && window->mode == BITMAP )
1135                 FillRect( updateRect );
1136 }
1137
1138 /*****************************************************************************
1139  * Local prototypes
1140  *****************************************************************************/
1141 static int  Init       ( vout_thread_t * );
1142 static void End        ( vout_thread_t * );
1143 // static int  Manage     ( vout_thread_t * );
1144 static void Display    ( vout_thread_t *, picture_t * );
1145
1146 static int  BeosOpenDisplay ( vout_thread_t *p_vout );
1147 static void BeosCloseDisplay( vout_thread_t *p_vout );
1148
1149 /*****************************************************************************
1150  * OpenVideo: allocates BeOS video thread output method
1151  *****************************************************************************
1152  * This function allocates and initializes a BeOS vout method.
1153  *****************************************************************************/
1154 int E_(OpenVideo) ( vlc_object_t *p_this )
1155 {
1156     vout_thread_t * p_vout = (vout_thread_t *)p_this;
1157
1158     /* Allocate structure */
1159     p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
1160     if( p_vout->p_sys == NULL )
1161     {
1162         msg_Err( p_vout, "out of memory" );
1163         return( 1 );
1164     }
1165     p_vout->p_sys->i_width = p_vout->render.i_width;
1166     p_vout->p_sys->i_height = p_vout->render.i_height;
1167     p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
1168
1169     p_vout->pf_init = Init;
1170     p_vout->pf_end = End;
1171     p_vout->pf_manage = NULL;
1172     p_vout->pf_render = NULL;
1173     p_vout->pf_display = Display;
1174
1175     return( 0 );
1176 }
1177
1178 /*****************************************************************************
1179  * Init: initialize BeOS video thread output method
1180  *****************************************************************************/
1181 int Init( vout_thread_t *p_vout )
1182 {
1183     int i_index;
1184     picture_t *p_pic;
1185
1186     I_OUTPUTPICTURES = 0;
1187
1188     /* Open and initialize device */
1189     if( BeosOpenDisplay( p_vout ) )
1190     {
1191         msg_Err(p_vout, "vout error: can't open display");
1192         return 0;
1193     }
1194     p_vout->output.i_width  = p_vout->render.i_width;
1195     p_vout->output.i_height = p_vout->render.i_height;
1196
1197     /* Assume we have square pixels */
1198     p_vout->output.i_aspect = p_vout->p_sys->i_width
1199                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
1200     p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
1201     p_vout->p_sys->i_index = 0;
1202
1203     p_vout->b_direct = 1;
1204
1205     p_vout->output.i_rmask  = 0x00ff0000;
1206     p_vout->output.i_gmask  = 0x0000ff00;
1207     p_vout->output.i_bmask  = 0x000000ff;
1208
1209     for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
1210     {
1211        p_pic = NULL;
1212        /* Find an empty picture slot */
1213        for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
1214        {
1215            p_pic = NULL;
1216            if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
1217            {
1218                p_pic = p_vout->p_picture + i_index;
1219                break;
1220            }
1221        }
1222
1223        if( p_pic == NULL )
1224        {
1225            return 0;
1226        }
1227        p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
1228        p_pic->p->i_lines = p_vout->p_sys->i_height;
1229
1230        p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
1231        p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
1232        p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow(); 
1233        p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
1234
1235        p_pic->i_status = DESTROYED_PICTURE;
1236        p_pic->i_type   = DIRECT_PICTURE;
1237  
1238        PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
1239
1240        I_OUTPUTPICTURES++;
1241     }
1242
1243     return( 0 );
1244 }
1245
1246 /*****************************************************************************
1247  * End: terminate BeOS video thread output method
1248  *****************************************************************************/
1249 void End( vout_thread_t *p_vout )
1250 {
1251     BeosCloseDisplay( p_vout );
1252 }
1253
1254 /*****************************************************************************
1255  * CloseVideo: destroy BeOS video thread output method
1256  *****************************************************************************
1257  * Terminate an output method created by DummyCreateOutputMethod
1258  *****************************************************************************/
1259 void E_(CloseVideo) ( vlc_object_t *p_this )
1260 {
1261     vout_thread_t * p_vout = (vout_thread_t *)p_this;
1262
1263     free( p_vout->p_sys );
1264 }
1265
1266 /*****************************************************************************
1267  * Display: displays previously rendered output
1268  *****************************************************************************
1269  * This function send the currently rendered image to BeOS image, waits until
1270  * it is displayed and switch the two rendering buffers, preparing next frame.
1271  *****************************************************************************/
1272 void Display( vout_thread_t *p_vout, picture_t *p_pic )
1273 {
1274     VideoWindow * p_win = p_vout->p_sys->p_window;
1275
1276     /* draw buffer if required */    
1277     if (!p_win->teardownwindow)
1278     { 
1279        p_win->drawBuffer(p_vout->p_sys->i_index);
1280     }
1281     /* change buffer */
1282     p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
1283     p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
1284 }
1285
1286 /* following functions are local */
1287
1288 /*****************************************************************************
1289  * BeosOpenDisplay: open and initialize BeOS device
1290  *****************************************************************************/
1291 static int BeosOpenDisplay( vout_thread_t *p_vout )
1292
1293
1294     p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
1295                                                p_vout->p_sys->i_height - 1,
1296                                                BRect( 20, 50,
1297                                                       20 + p_vout->i_window_width - 1, 
1298                                                       50 + p_vout->i_window_height - 1 ),
1299                                                p_vout );
1300     if( p_vout->p_sys->p_window == NULL )
1301     {
1302         msg_Err( p_vout, "cannot allocate VideoWindow" );
1303         return( 1 );
1304     }
1305     else
1306     {
1307         p_vout->p_sys->p_window->Show();
1308     }
1309     
1310     return( 0 );
1311 }
1312
1313 /*****************************************************************************
1314  * BeosDisplay: close and reset BeOS device
1315  *****************************************************************************
1316  * Returns all resources allocated by BeosOpenDisplay and restore the original
1317  * state of the device.
1318  *****************************************************************************/
1319 static void BeosCloseDisplay( vout_thread_t *p_vout )
1320 {    
1321     VideoWindow * p_win = p_vout->p_sys->p_window;
1322     /* Destroy the video window */
1323     if( p_win != NULL && !p_win->teardownwindow)
1324     {
1325         p_win->Lock();
1326         p_win->teardownwindow = true;
1327         p_win->Hide();
1328         p_win->Quit();
1329     }
1330     p_win = NULL;
1331 }