Implemented simple right click menu
[vlc.git] / plugins / beos / vout_beos.cpp
1 /*****************************************************************************
2  * vout_beos.cpp: beos video output display method
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: vout_beos.cpp,v 1.62 2002/07/22 11:39:56 tcastley 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  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdlib.h>                                                /* free() */
32 #include <stdio.h>
33 #include <string.h>                                            /* strerror() */
34 #include <InterfaceKit.h>
35 #include <DirectWindow.h>
36 #include <Application.h>
37 #include <Bitmap.h>
38
39 #include <vlc/vlc.h>
40 #include <vlc/intf.h>
41 #include <vlc/vout.h>
42
43 #include "VideoWindow.h"
44 #include "DrawingTidbits.h"
45 #include "MsgVals.h"
46
47
48 /*****************************************************************************
49  * vout_sys_t: BeOS video output method descriptor
50  *****************************************************************************
51  * This structure is part of the video output thread descriptor.
52  * It describes the BeOS specific properties of an output thread.
53  *****************************************************************************/
54 struct vout_sys_t
55 {
56     VideoWindow *  p_window;
57
58     s32 i_width;
59     s32 i_height;
60
61     u32 source_chroma;
62     int i_index;
63 };
64
65 /*****************************************************************************
66  * beos_GetAppWindow : retrieve a BWindow pointer from the window name
67  *****************************************************************************/
68 BWindow *beos_GetAppWindow(char *name)
69 {
70     int32       index;
71     BWindow     *window;
72     
73     for (index = 0 ; ; index++)
74     {
75         window = be_app->WindowAt(index);
76         if (window == NULL)
77             break;
78         if (window->LockWithTimeout(20000) == B_OK)
79         {
80             if (strcmp(window->Name(), name) == 0)
81             {
82                 window->Unlock();
83                 break;
84             }
85             window->Unlock();
86         }
87     }
88     return window; 
89 }
90
91 /*****************************************************************************
92  * VideoWindow constructor and destructor
93  *****************************************************************************/
94 VideoWindow::VideoWindow( int v_width, int v_height, 
95                           BRect frame )
96             : BWindow( frame, NULL, B_TITLED_WINDOW, 
97                     B_NOT_CLOSABLE | B_NOT_MINIMIZABLE )
98 {
99     BView *mainView =  new BView( Bounds(), "mainView", 
100                                   B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE);
101     AddChild(mainView);
102     mainView->SetViewColor(kBlack);
103                                   
104     /* create the view to do the display */
105     view = new VLCView( Bounds() );
106     mainView->AddChild(view);
107
108     /* set the VideoWindow variables */
109     teardownwindow = false;
110     is_zoomed = false;
111     i_buffer = 0;
112
113     /* call ScreenChanged to set vsync correctly */
114     BScreen *screen;
115     display_mode disp_mode; 
116     float refresh;
117
118     screen = new BScreen(this);
119     
120     screen-> GetMode(&disp_mode); 
121     refresh = 
122          (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)* 
123          (disp_mode.timing.v_total)); 
124     if (refresh  < 61) 
125     { 
126         vsync = true; 
127     } 
128     delete screen;
129     
130     mode = SelectDrawingMode(v_width, v_height);
131
132     // remember current settings
133     i_width = frame.IntegerWidth();
134     i_height = frame.IntegerHeight();
135     FrameResized(frame.IntegerWidth(), frame.IntegerHeight());
136
137     if (mode == OVERLAY)
138     {
139        overlay_restrictions r;
140
141        bitmap[1]->GetOverlayRestrictions(&r);
142        SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
143                      (i_height * r.min_height_scale), i_height * r.max_height_scale);
144     }
145     Show();
146 }
147
148 VideoWindow::~VideoWindow()
149 {
150     teardownwindow = true;
151     delete bitmap[0];
152     delete bitmap[1];
153     delete bitmap[2];
154 }
155
156 void VideoWindow::MessageReceived( BMessage *p_message )
157 {
158     switch( p_message->what )
159     {
160     case TOGGLE_FULL_SCREEN:
161         ((BWindow *)this)->Zoom();
162         break;
163     case RESIZE_100:
164         if (is_zoomed)
165         {
166            ((BWindow *)this)->Zoom();
167         }
168         ResizeTo(i_width, i_height);
169         break;
170     case RESIZE_200:
171         if (is_zoomed)
172         {
173            ((BWindow *)this)->Zoom();
174         }
175         ResizeTo(i_width * 2, i_height * 2);
176         break;
177     case VERT_SYNC:
178         vsync = !vsync;
179         break;
180     case WINDOW_FEEL:
181         {
182             int16 winFeel;
183             if (p_message->FindInt16("WinFeel", &winFeel) == B_OK)
184             {
185                 SetFeel((window_feel)winFeel);
186             }
187         }
188         break;
189     default:
190         BWindow::MessageReceived( p_message );
191         break;
192     }
193 }
194
195 void VideoWindow::drawBuffer(int bufferIndex)
196 {
197     i_buffer = bufferIndex;
198
199     // sync to the screen if required
200     if (vsync)
201     {
202         BScreen *screen;
203         screen = new BScreen(this);
204         screen-> WaitForRetrace(22000);
205         delete screen;
206     }
207     if (LockLooper())
208     {
209        // switch the overlay bitmap
210        if (mode == OVERLAY)
211        {
212           rgb_color key;
213           view->SetViewOverlay(bitmap[i_buffer], 
214                             bitmap[i_buffer]->Bounds() ,
215                             view->Bounds(),
216                             &key, B_FOLLOW_ALL,
217                                     B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
218                                     B_OVERLAY_TRANSFER_CHANNEL);
219                    view->SetViewColor(key);
220            }
221        else
222        {
223          // switch the bitmap
224          view-> DrawBitmap(bitmap[i_buffer], view->Bounds() );
225        }
226        UnlockLooper();
227     }
228 }
229
230 void VideoWindow::Zoom(BPoint origin, float width, float height )
231 {
232     if(is_zoomed)
233     {
234         is_zoomed = !is_zoomed;
235         MoveTo(winSize.left, winSize.top);
236         ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
237         be_app->ShowCursor();
238     }
239     else
240     {
241         is_zoomed = !is_zoomed;
242         BScreen *screen;
243         screen = new BScreen(this);
244         BRect rect = screen->Frame();
245         delete screen;
246         MoveTo(0,0);
247         ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
248         be_app->ObscureCursor();
249     }
250 }
251
252 void VideoWindow::FrameMoved(BPoint origin) 
253 {
254         if (is_zoomed) return ;
255     winSize = Frame();
256 }
257
258 void VideoWindow::FrameResized( float width, float height )
259 {
260     float out_width, out_height;
261     float out_left, out_top;
262     float width_scale = width / i_width;
263     float height_scale = height / i_height;
264
265     if (width_scale <= height_scale)
266     {
267         out_width = (i_width * width_scale);
268         out_height = (i_height * width_scale);
269         out_left = 0; 
270         out_top = (height - out_height) / 2;
271     }
272     else   /* if the height is proportionally smaller */
273     {
274         out_width = (i_width * height_scale);
275         out_height = (i_height * height_scale);
276         out_top = 0;
277         out_left = (width - out_width) /2;
278     }
279     view->MoveTo(out_left,out_top);
280     view->ResizeTo(out_width, out_height);
281         if (!is_zoomed)
282         {
283         winSize = Frame();
284     }
285 }
286
287 void VideoWindow::ScreenChanged(BRect frame, color_space mode)
288 {
289     BScreen *screen;
290     float refresh;
291     
292     screen = new BScreen(this);
293     display_mode disp_mode; 
294     
295     screen-> GetMode(&disp_mode); 
296     refresh = 
297          (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)* 
298          (disp_mode.timing.v_total)); 
299     if (refresh  < 61) 
300     { 
301         vsync = true; 
302     } 
303 }
304
305 void VideoWindow::WindowActivated(bool active)
306 {
307 }
308
309 int VideoWindow::SelectDrawingMode(int width, int height)
310 {
311     int drawingMode = BITMAP;
312     int noOverlay = 0;
313
314 //    int noOverlay = !config_GetIntVariable( "overlay" );
315     for (int i = 0; i < COLOR_COUNT; i++)
316     {
317         if (noOverlay) break;
318         bitmap[0] = new BBitmap ( BRect( 0, 0, width, height ), 
319                                   B_BITMAP_WILL_OVERLAY,
320                                   colspace[i].colspace);
321
322         if(bitmap[0] && bitmap[0]->InitCheck() == B_OK) 
323         {
324             colspace_index = i;
325
326             bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY,
327                                      colspace[colspace_index].colspace);
328             bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY,
329                                      colspace[colspace_index].colspace);
330             if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
331             {
332                drawingMode = OVERLAY;
333                rgb_color key;
334                view->SetViewOverlay(bitmap[0], 
335                                     bitmap[0]->Bounds() ,
336                                     view->Bounds(),
337                                     &key, B_FOLLOW_ALL,
338                                             B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
339                        view->SetViewColor(key);
340                SetTitle(VOUT_TITLE " (Overlay)");
341                break;
342             }
343             else
344             {
345                delete bitmap[0];
346                delete bitmap[1];
347                delete bitmap[2];
348             }
349         }
350         else
351         {
352             delete bitmap[0];
353         }        
354         }
355
356     if (drawingMode == BITMAP)
357         {
358         // fallback to RGB16
359         colspace_index = DEFAULT_COL;
360         SetTitle(VOUT_TITLE " (Bitmap)");
361         bitmap[0] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
362         bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
363         bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
364     }
365     return drawingMode;
366 }
367
368 /*****************************************************************************
369  * VLCView::VLCView
370  *****************************************************************************/
371 VLCView::VLCView(BRect bounds) : BView(bounds, "", B_FOLLOW_NONE,
372                                        B_WILL_DRAW)
373
374 {
375     SetViewColor(B_TRANSPARENT_32_BIT);
376 }
377
378 /*****************************************************************************
379  * VLCView::~VLCView
380  *****************************************************************************/
381 VLCView::~VLCView()
382 {
383 }
384
385 /*****************************************************************************
386  * VLCVIew::MouseDown
387  *****************************************************************************/
388 void VLCView::MouseDown(BPoint point)
389 {
390     BMessage* msg = Window()->CurrentMessage();
391     int32 clicks = msg->FindInt32("clicks");
392
393     VideoWindow *vWindow = (VideoWindow *)Window();
394     uint32 mouseButtons;
395     BPoint where;
396     GetMouse(&where, &mouseButtons, true);
397
398     if ((mouseButtons & B_PRIMARY_MOUSE_BUTTON) && (clicks == 2))
399     {
400        Window()->Zoom();
401        return;
402     }
403     else
404     {
405        if (mouseButtons & B_SECONDARY_MOUSE_BUTTON) 
406        {
407            BPopUpMenu *menu = new BPopUpMenu("context menu");
408            menu->SetRadioMode(false);
409            // Toggle FullScreen
410            BMenuItem *zoomItem = new BMenuItem("Fullscreen", new BMessage(TOGGLE_FULL_SCREEN));
411            zoomItem->SetMarked(vWindow->is_zoomed);
412            menu->AddItem(zoomItem);
413            // Resize to 100%
414            BMenuItem *origItem = new BMenuItem("100%", new BMessage(RESIZE_100));
415            menu->AddItem(origItem);
416            // Resize to 200%
417            BMenuItem *doubleItem = new BMenuItem("200%", new BMessage(RESIZE_200));
418            menu->AddItem(doubleItem);
419            menu->AddSeparatorItem();
420            // Toggle vSync
421            BMenuItem *vsyncItem = new BMenuItem("Vertical Sync", new BMessage(VERT_SYNC));
422            vsyncItem->SetMarked(vWindow->vsync);
423            menu->AddItem(vsyncItem);
424            menu->AddSeparatorItem();
425
426                    // Windwo Feel Items
427                    BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
428                    winNormFeel->AddInt16("WinFeel", (int16)B_NORMAL_WINDOW_FEEL);
429            BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
430            normWindItem->SetMarked(vWindow->Feel() == B_NORMAL_WINDOW_FEEL);
431            menu->AddItem(normWindItem);
432            
433                    BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
434                    winFloatFeel->AddInt16("WinFeel", (int16)B_FLOATING_APP_WINDOW_FEEL);
435            BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
436            onTopWindItem->SetMarked(vWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
437            menu->AddItem(onTopWindItem);
438            
439                    BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
440                    winAllFeel->AddInt16("WinFeel", (int16)B_FLOATING_ALL_WINDOW_FEEL);
441            BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
442            allSpacesWindItem->SetMarked(vWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
443            menu->AddItem(allSpacesWindItem);
444                    
445            menu->SetTargetForItems(this);
446            ConvertToScreen(&where);
447            menu->Go(where, true, false, true);
448         }
449         } 
450 }
451
452 /*****************************************************************************
453  * VLCVIew::Draw
454  *****************************************************************************/
455 void VLCView::Draw(BRect updateRect) 
456 {
457     VideoWindow *win = (VideoWindow *) Window();
458     if (win->mode == BITMAP)
459       FillRect(updateRect);
460 }
461
462
463 extern "C"
464 {
465
466 /*****************************************************************************
467  * Local prototypes
468  *****************************************************************************/
469 static int  vout_Create     ( vout_thread_t * );
470 static int  vout_Init       ( vout_thread_t * );
471 static void vout_End        ( vout_thread_t * );
472 static void vout_Destroy    ( vout_thread_t * );
473 static int  vout_Manage     ( vout_thread_t * );
474 static void vout_Display    ( vout_thread_t *, picture_t * );
475 static void vout_Render     ( vout_thread_t *, picture_t * );
476
477 static int  BeosOpenDisplay ( vout_thread_t *p_vout );
478 static void BeosCloseDisplay( vout_thread_t *p_vout );
479
480 /*****************************************************************************
481  * Functions exported as capabilities. They are declared as static so that
482  * we don't pollute the namespace too much.
483  *****************************************************************************/
484 void _M( vout_getfunctions )( function_list_t * p_function_list )
485 {
486     p_function_list->functions.vout.pf_create     = vout_Create;
487     p_function_list->functions.vout.pf_init       = vout_Init;
488     p_function_list->functions.vout.pf_end        = vout_End;
489     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
490     p_function_list->functions.vout.pf_manage     = vout_Manage;
491     p_function_list->functions.vout.pf_display    = vout_Display;
492     p_function_list->functions.vout.pf_render     = vout_Render;
493 }
494
495 /*****************************************************************************
496  * vout_Create: allocates BeOS video thread output method
497  *****************************************************************************
498  * This function allocates and initializes a BeOS vout method.
499  *****************************************************************************/
500 int vout_Create( vout_thread_t *p_vout )
501 {
502     /* Allocate structure */
503     p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
504     if( p_vout->p_sys == NULL )
505     {
506         msg_Err( p_vout, "out of memory" );
507         return( 1 );
508     }
509     p_vout->p_sys->i_width = p_vout->render.i_width;
510     p_vout->p_sys->i_height = p_vout->render.i_height;
511     p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
512
513     return( 0 );
514 }
515
516 /*****************************************************************************
517  * vout_Init: initialize BeOS video thread output method
518  *****************************************************************************/
519 int vout_Init( vout_thread_t *p_vout )
520 {
521     int i_index;
522     picture_t *p_pic;
523
524     I_OUTPUTPICTURES = 0;
525
526     /* Open and initialize device */
527     if( BeosOpenDisplay( p_vout ) )
528     {
529         msg_Err(p_vout, "vout error: can't open display");
530         return 0;
531     }
532     p_vout->output.i_width  = p_vout->render.i_width;
533     p_vout->output.i_height = p_vout->render.i_height;
534
535     /* Assume we have square pixels */
536     p_vout->output.i_aspect = p_vout->p_sys->i_width
537                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
538     p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
539     p_vout->p_sys->i_index = 0;
540
541     p_vout->b_direct = 1;
542
543     p_vout->output.i_rmask  = 0x00ff0000;
544     p_vout->output.i_gmask  = 0x0000ff00;
545     p_vout->output.i_bmask  = 0x000000ff;
546
547     for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
548     {
549        p_pic = NULL;
550        /* Find an empty picture slot */
551        for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
552        {
553            p_pic = NULL;
554            if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
555            {
556                p_pic = p_vout->p_picture + i_index;
557                break;
558            }
559        }
560
561        if( p_pic == NULL )
562        {
563            return 0;
564        }
565        p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
566        p_pic->p->i_lines = p_vout->p_sys->i_height;
567
568        p_pic->p->i_pixel_bytes = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
569        p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
570        p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow(); 
571
572        if (p_vout->p_sys->p_window->mode == OVERLAY)
573        {
574           p_pic->p->i_visible_bytes = (p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth()+1) 
575                                      * p_pic->p->i_pixel_bytes; 
576           p_pic->p->b_margin = 1;
577           p_pic->p->b_hidden = 0;
578        }
579        else
580        {
581           p_pic->p->b_margin = 0;
582           p_pic->p->i_visible_bytes = p_pic->p->i_pitch;
583        }
584
585        p_pic->i_status = DESTROYED_PICTURE;
586        p_pic->i_type   = DIRECT_PICTURE;
587  
588        PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
589
590        I_OUTPUTPICTURES++;
591     }
592
593     return( 0 );
594 }
595
596 /*****************************************************************************
597  * vout_End: terminate BeOS video thread output method
598  *****************************************************************************/
599 void vout_End( vout_thread_t *p_vout )
600 {
601     BeosCloseDisplay( p_vout );
602 }
603
604 /*****************************************************************************
605  * vout_Destroy: destroy BeOS video thread output method
606  *****************************************************************************
607  * Terminate an output method created by DummyCreateOutputMethod
608  *****************************************************************************/
609 void vout_Destroy( vout_thread_t *p_vout )
610 {
611     free( p_vout->p_sys );
612 }
613
614 /*****************************************************************************
615  * vout_Manage: handle BeOS events
616  *****************************************************************************
617  * This function should be called regularly by video output thread. It manages
618  * console events. It returns a non null value on error.
619  *****************************************************************************/
620 int vout_Manage( vout_thread_t *p_vout )
621 {
622                           
623     return( 0 );
624 }
625
626 /*****************************************************************************
627  * vout_Render: render previously calculated output
628  *****************************************************************************/
629 void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
630 {
631     ;
632 }
633
634 /*****************************************************************************
635  * vout_Display: displays previously rendered output
636  *****************************************************************************
637  * This function send the currently rendered image to BeOS image, waits until
638  * it is displayed and switch the two rendering buffers, preparing next frame.
639  *****************************************************************************/
640 void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
641 {
642     VideoWindow * p_win = p_vout->p_sys->p_window;
643
644     /* draw buffer if required */    
645     if (!p_win->teardownwindow)
646     { 
647        p_win->drawBuffer(p_vout->p_sys->i_index);
648     }
649     /* change buffer */
650     p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
651     p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
652 }
653
654 /* following functions are local */
655
656 /*****************************************************************************
657  * BeosOpenDisplay: open and initialize BeOS device
658  *****************************************************************************/
659 static int BeosOpenDisplay( vout_thread_t *p_vout )
660
661
662     p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
663                                                p_vout->p_sys->i_height - 1,
664                                                BRect( 20, 50,
665                                                       20 + p_vout->i_window_width - 1, 
666                                                       50 + p_vout->i_window_height - 1 ));
667
668     if( p_vout->p_sys->p_window == NULL )
669     {
670         msg_Err( p_vout, "cannot allocate VideoWindow" );
671         return( 1 );
672     }   
673     
674     return( 0 );
675 }
676
677 /*****************************************************************************
678  * BeosDisplay: close and reset BeOS device
679  *****************************************************************************
680  * Returns all resources allocated by BeosOpenDisplay and restore the original
681  * state of the device.
682  *****************************************************************************/
683 static void BeosCloseDisplay( vout_thread_t *p_vout )
684 {    
685     VideoWindow * p_win = p_vout->p_sys->p_window;
686     /* Destroy the video window */
687     if( p_win != NULL && !p_win->teardownwindow)
688     {
689         p_win->Lock();
690         p_win->teardownwindow = true;
691         p_win->Hide();
692         p_win->Quit();
693     }
694     p_win = NULL;
695 }
696
697
698
699 } /* extern "C" */