]> git.sesse.net Git - vlc/blob - projects/mozilla/vlcshell.cpp
mozilla: sanity checks
[vlc] / projects / mozilla / vlcshell.cpp
1 /*****************************************************************************
2  * vlcshell.cpp: a VLC plugin for Mozilla
3  *****************************************************************************
4  * Copyright (C) 2002-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          Jean-Paul Saman <jpsaman@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 /* Mozilla stuff */
35 #ifdef HAVE_MOZILLA_CONFIG_H
36 #   include <mozilla-config.h>
37 #endif
38
39 /* This is from mozilla java, do we really need it? */
40 #if 0
41 #include <jri.h>
42 #endif
43
44 #include "vlcplugin.h"
45 #include "vlcshell.h"
46
47 /* Enable/disable debugging printf's for X11 resizing */
48 #undef X11_RESIZE_DEBUG
49
50 /*****************************************************************************
51  * Unix-only declarations
52 ******************************************************************************/
53 #if defined(XP_UNIX)
54
55 static void Redraw( Widget w, XtPointer closure, XEvent *event );
56 static void ControlHandler( Widget w, XtPointer closure, XEvent *event );
57 static void Resize( Widget w, XtPointer closure, XEvent *event );
58
59 #endif
60
61 /*****************************************************************************
62  * MacOS-only declarations
63 ******************************************************************************/
64 #ifdef XP_MACOSX
65 #endif
66
67 /*****************************************************************************
68  * Windows-only declarations
69  *****************************************************************************/
70 #ifdef XP_WIN
71
72 static LRESULT CALLBACK Manage( HWND p_hwnd, UINT i_msg, WPARAM wpar, LPARAM lpar );
73
74 #endif
75
76 /******************************************************************************
77  * UNIX-only API calls
78  *****************************************************************************/
79 char * NPP_GetMIMEDescription( void )
80 {
81     static char mimetype[] = PLUGIN_MIMETYPES;
82     return mimetype;
83 }
84
85 NPError NPP_GetValue( NPP instance, NPPVariable variable, void *value )
86 {
87     static char psz_name[] = PLUGIN_NAME;
88     static char psz_desc[1000];
89
90     /* plugin class variables */
91     switch( variable )
92     {
93         case NPPVpluginNameString:
94             *((char **)value) = psz_name;
95             return NPERR_NO_ERROR;
96
97         case NPPVpluginDescriptionString:
98             snprintf( psz_desc, sizeof(psz_desc), PLUGIN_DESCRIPTION,
99                       libvlc_get_version() );
100             *((char **)value) = psz_desc;
101             return NPERR_NO_ERROR;
102
103         default:
104             /* move on to instance variables ... */
105             ;
106     }
107
108     if( instance == NULL )
109     {
110         return NPERR_INVALID_INSTANCE_ERROR;
111     }
112
113     /* plugin instance variables */
114
115     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
116     if( NULL == p_plugin )
117     {
118         // plugin has not been initialized yet !
119         return NPERR_INVALID_INSTANCE_ERROR;
120     }
121
122     switch( variable )
123     {
124         case NPPVpluginScriptableNPObject:
125         {
126             /* retrieve plugin root class */
127             NPClass *scriptClass = p_plugin->getScriptClass();
128             if( scriptClass )
129             {
130                 /* create an instance and return it */
131                 *(NPObject**)value = NPN_CreateObject(instance, scriptClass);
132                 return NPERR_NO_ERROR;
133             }
134             break;
135         }
136
137         default:
138             ;
139     }
140     return NPERR_GENERIC_ERROR;
141 }
142
143 /*
144  * there is some confusion in gecko headers regarding definition of this API
145  * NPPVariable is wrongly defined as NPNVariable, which sounds incorrect.
146  */
147
148 NPError NPP_SetValue( NPP instance, NPNVariable variable, void *value )
149 {
150     return NPERR_GENERIC_ERROR;
151 }
152
153 /******************************************************************************
154  * Mac-only API calls
155  *****************************************************************************/
156 #ifdef XP_MACOSX
157 int16 NPP_HandleEvent( NPP instance, void * event )
158 {
159     static UInt32 lastMouseUp = 0;
160     if( instance == NULL )
161     {
162         return false;
163     }
164
165     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
166     if( p_plugin == NULL )
167     {
168         return false;
169     }
170
171     EventRecord *myEvent = (EventRecord*)event;
172
173     switch( myEvent->what )
174     {
175         case nullEvent:
176             return true;
177         case mouseDown:
178         {
179             if( (myEvent->when - lastMouseUp) < GetDblTime() )
180             {
181                 /* double click */
182                 p_plugin->toggle_fullscreen();
183             }
184             return true;
185         }
186         case mouseUp:
187             lastMouseUp = myEvent->when;
188             return true;
189         case keyUp:
190         case keyDown:
191         case autoKey:
192             return true;
193         case updateEvt:
194         {
195             const NPWindow& npwindow = p_plugin->getWindow();
196             if( npwindow.window )
197             {
198                 bool hasVout = false;
199
200                 if( p_plugin->playlist_isplaying() )
201                 {
202                     hasVout = p_plugin->player_has_vout(NULL);
203                     if( hasVout )
204                     {
205 #ifdef NOT_WORKING
206                         libvlc_rectangle_t area;
207                         area.left = 0;
208                         area.top = 0;
209                         area.right = npwindow.width;
210                         area.bottom = npwindow.height;
211                         libvlc_video_redraw_rectangle(p_plugin->getMD(), &area, NULL);
212 #else
213 #warning disabled code
214 #endif
215                     }
216                 }
217
218                 if( ! hasVout )
219                 {
220                     /* draw the beautiful "No Picture" */
221
222                     ForeColor(blackColor);
223                     PenMode( patCopy );
224
225                     /* seems that firefox forgets to set the following
226                      * on occasion (reload) */
227                     SetOrigin(((NP_Port *)npwindow.window)->portx,
228                               ((NP_Port *)npwindow.window)->porty);
229
230                     Rect rect;
231                     rect.left = 0;
232                     rect.top = 0;
233                     rect.right = npwindow.width;
234                     rect.bottom = npwindow.height;
235                     PaintRect( &rect );
236
237                     ForeColor(whiteColor);
238                     MoveTo( (npwindow.width-80)/ 2  , npwindow.height / 2 );
239                     if( p_plugin->psz_text )
240                         DrawText( p_plugin->psz_text, 0, strlen(p_plugin->psz_text) );
241                 }
242             }
243             return true;
244         }
245         case activateEvt:
246             return false;
247         case NPEventType_GetFocusEvent:
248         case NPEventType_LoseFocusEvent:
249             return true;
250         case NPEventType_AdjustCursorEvent:
251             return false;
252         case NPEventType_MenuCommandEvent:
253             return false;
254         case NPEventType_ClippingChangedEvent:
255             return false;
256         case NPEventType_ScrollingBeginsEvent:
257             return true;
258         case NPEventType_ScrollingEndsEvent:
259             return true;
260         default:
261             ;
262     }
263     return false;
264 }
265 #endif /* XP_MACOSX */
266
267 /******************************************************************************
268  * General Plug-in Calls
269  *****************************************************************************/
270 NPError NPP_Initialize( void )
271 {
272     return NPERR_NO_ERROR;
273 }
274
275 jref NPP_GetJavaClass( void )
276 {
277     return NULL;
278 }
279
280 void NPP_Shutdown( void )
281 {
282     ;
283 }
284
285 NPError NPP_New( NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
286                  char* argn[], char* argv[], NPSavedData* saved )
287 {
288     NPError status;
289
290     if( instance == NULL )
291     {
292         return NPERR_INVALID_INSTANCE_ERROR;
293     }
294
295     VlcPlugin * p_plugin = new VlcPlugin( instance, mode );
296     if( NULL == p_plugin )
297     {
298         return NPERR_OUT_OF_MEMORY_ERROR;
299     }
300
301     status = p_plugin->init(argc, argn, argv);
302     if( NPERR_NO_ERROR == status )
303     {
304         instance->pdata = reinterpret_cast<void*>(p_plugin);
305 #if 0
306         NPN_SetValue(instance, NPPVpluginWindowBool, (void *)false);
307         NPN_SetValue(instance, NPPVpluginTransparentBool, (void *)false);
308 #endif
309     }
310     else
311     {
312         delete p_plugin;
313     }
314     return status;
315 }
316
317 NPError NPP_Destroy( NPP instance, NPSavedData** save )
318 {
319     if( NULL == instance )
320         return NPERR_INVALID_INSTANCE_ERROR;
321
322     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
323     if( NULL == p_plugin )
324         return NPERR_NO_ERROR;
325
326     instance->pdata = NULL;
327
328 #if defined(XP_WIN)
329     HWND win = (HWND)p_plugin->getWindow().window;
330     WNDPROC winproc = p_plugin->getWindowProc();
331     if( winproc )
332     {
333         /* reset WNDPROC */
334         SetWindowLong( win, GWL_WNDPROC, (LONG)winproc );
335     }
336 #endif
337
338     if( p_plugin->playlist_isplaying() )
339         p_plugin->playlist_stop();
340
341     delete p_plugin;
342
343     return NPERR_NO_ERROR;
344 }
345
346 NPError NPP_SetWindow( NPP instance, NPWindow* window )
347 {
348 #if defined(XP_UNIX)
349     Window control;
350     unsigned int i_control_height = 0, i_control_width = 0;
351 #endif
352
353     if( ! instance )
354     {
355         return NPERR_INVALID_INSTANCE_ERROR;
356     }
357
358     /* NPP_SetWindow may be called before NPP_New (Opera) */
359     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(instance->pdata);
360     if( NULL == p_plugin )
361     {
362         /* we should probably show a splash screen here */
363         return NPERR_NO_ERROR;
364     }
365
366 #if defined(XP_UNIX)
367     control = p_plugin->getControlWindow();
368 #endif
369
370     libvlc_instance_t *p_vlc = p_plugin->getVLC();
371
372     /*
373      * PLUGIN DEVELOPERS:
374      *  Before setting window to point to the
375      *  new window, you may wish to compare the new window
376      *  info to the previous window (if any) to note window
377      *  size changes, etc.
378      */
379
380     /* retrieve current window */
381     NPWindow& curwin = p_plugin->getWindow();
382
383 #ifdef XP_MACOSX
384     if( window && window->window )
385     {
386         /* check if plugin has a new parent window */
387         CGrafPtr drawable = (((NP_Port*) (window->window))->port);
388
389         /* as MacOS X video output is windowless, set viewport */
390         libvlc_rectangle_t view, clip;
391
392         /*
393         ** browser sets port origin to top-left location of plugin
394         ** relative to GrafPort window origin is set relative to document,
395         ** which of little use for drawing
396         */
397         view.top     = ((NP_Port*) (window->window))->porty;
398         view.left    = ((NP_Port*) (window->window))->portx;
399         view.bottom  = window->height+view.top;
400         view.right   = window->width+view.left;
401
402         /* clipRect coordinates are also relative to GrafPort */
403         clip.top     = window->clipRect.top;
404         clip.left    = window->clipRect.left;
405         clip.bottom  = window->clipRect.bottom;
406         clip.right   = window->clipRect.right;
407 #ifdef NOT_WORKING
408         libvlc_video_set_viewport(p_vlc, p_plugin->getMD(), &view, &clip);
409 #else
410 #warning disabled code
411 #endif
412         /* remember new window */
413         p_plugin->setWindow(*window);
414     }
415     else if( curwin.window )
416     {
417         /* change/set parent */
418         curwin.window = NULL;
419     }
420 #endif /* XP_MACOSX */
421
422 #ifdef XP_WIN
423     if( window && window->window )
424     {
425         /* check if plugin has a new parent window */
426         HWND drawable = (HWND) (window->window);
427         if( !curwin.window || drawable != curwin.window )
428         {
429             /* reset previous window settings */
430             HWND oldwin = (HWND)p_plugin->getWindow().window;
431             WNDPROC oldproc = p_plugin->getWindowProc();
432             if( oldproc )
433             {
434                 /* reset WNDPROC */
435                 SetWindowLong( oldwin, GWL_WNDPROC, (LONG)oldproc );
436             }
437             /* attach our plugin object */
438             SetWindowLongPtr((HWND)drawable, GWLP_USERDATA,
439                              reinterpret_cast<LONG_PTR>(p_plugin));
440
441             /* install our WNDPROC */
442             p_plugin->setWindowProc( (WNDPROC)SetWindowLong( drawable,
443                                              GWL_WNDPROC, (LONG)Manage ) );
444
445             /* change window style to our liking */
446             LONG style = GetWindowLong((HWND)drawable, GWL_STYLE);
447             style |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
448             SetWindowLong((HWND)drawable, GWL_STYLE, style);
449
450             /* remember new window */
451             p_plugin->setWindow(*window);
452
453             /* Redraw window */
454             InvalidateRect( (HWND)drawable, NULL, TRUE );
455             UpdateWindow( (HWND)drawable );
456         }
457     }
458     else if( curwin.window )
459     {
460         /* reset WNDPROC */
461         HWND oldwin = (HWND)curwin.window;
462         SetWindowLong( oldwin, GWL_WNDPROC, (LONG)(p_plugin->getWindowProc()) );
463         p_plugin->setWindowProc(NULL);
464
465         curwin.window = NULL;
466     }
467 #endif /* XP_WIN */
468
469 #if defined(XP_UNIX)
470     /* default to hidden toolbar, shown at the end of this method if asked *
471      * developers note : getToolbarSize need to wait the end of this method
472      */
473     i_control_height = 0;
474     i_control_width = window->width;
475
476     if( window && window->window )
477     {
478         Window  parent  = (Window) window->window;
479         if( !curwin.window || (parent != (Window)curwin.window) )
480         {
481             Display *p_display = ( (NPSetWindowCallbackStruct *)
482                                    window->ws_info )->display;
483
484             XResizeWindow( p_display, parent, window->width, window->height );
485
486             int i_blackColor = BlackPixel(p_display, DefaultScreen(p_display));
487
488             /* create windows */
489             Window video = XCreateSimpleWindow( p_display, parent, 0, 0,
490                            window->width, window->height - i_control_height,
491                            0, i_blackColor, i_blackColor );
492             Window controls = (Window) NULL;
493             controls = XCreateSimpleWindow( p_display, parent,
494                             0, window->height - i_control_height-1,
495                             window->width, i_control_height-1,
496                             0, i_blackColor, i_blackColor );
497
498             XMapWindow( p_display, parent );
499             XMapWindow( p_display, video );
500             if( controls ) { XMapWindow( p_display, controls ); }
501
502             XFlush(p_display);
503
504             /* bind events */
505             Widget w = XtWindowToWidget( p_display, parent );
506
507             XtAddEventHandler( w, ExposureMask, FALSE,
508                                (XtEventHandler)Redraw, p_plugin );
509             XtAddEventHandler( w, StructureNotifyMask, FALSE,
510                                (XtEventHandler)Resize, p_plugin );
511             XtAddEventHandler( w, ButtonReleaseMask, FALSE,
512                                (XtEventHandler)ControlHandler, p_plugin );
513
514             /* remember window */
515             p_plugin->setWindow( *window );
516             p_plugin->setVideoWindow( video );
517
518             if( controls )
519             {
520                 p_plugin->setControlWindow( controls );
521             }
522
523             Redraw( w, (XtPointer)p_plugin, NULL );
524
525             /* now display toolbar if asked through parameters */
526             if( p_plugin->b_toolbar )
527             {
528                 p_plugin->showToolbar();
529             }
530         }
531     }
532     else if( curwin.window )
533     {
534         curwin.window = NULL;
535     }
536 #endif /* XP_UNIX */
537
538     if( !p_plugin->b_stream )
539     {
540         if( p_plugin->psz_target )
541         {
542             if( p_plugin->playlist_add( p_plugin->psz_target ) != -1 )
543             {
544                 if( p_plugin->b_autoplay )
545                 {
546                     p_plugin->playlist_play();
547                 }
548             }
549             p_plugin->b_stream = true;
550         }
551     }
552     return NPERR_NO_ERROR;
553 }
554
555 NPError NPP_NewStream( NPP instance, NPMIMEType type, NPStream *stream,
556                        NPBool seekable, uint16 *stype )
557 {
558     if( NULL == instance  )
559     {
560         return NPERR_INVALID_INSTANCE_ERROR;
561     }
562
563     VlcPlugin *p_plugin = reinterpret_cast<VlcPlugin *>(instance->pdata);
564     if( NULL == p_plugin )
565     {
566         return NPERR_INVALID_INSTANCE_ERROR;
567     }
568
569    /*
570    ** Firefox/Mozilla may decide to open a stream from the URL specified
571    ** in the SRC parameter of the EMBED tag and pass it to us
572    **
573    ** since VLC will open the SRC URL as well, we're not interested in
574    ** that stream. Otherwise, we'll take it and queue it up in the playlist
575    */
576     if( !p_plugin->psz_target || strcmp(stream->url, p_plugin->psz_target) )
577     {
578         /* TODO: use pipes !!!! */
579         *stype = NP_ASFILEONLY;
580         return NPERR_NO_ERROR;
581     }
582     return NPERR_GENERIC_ERROR;
583 }
584
585 int32 NPP_WriteReady( NPP instance, NPStream *stream )
586 {
587     /* TODO */
588     return 8*1024;
589 }
590
591 int32 NPP_Write( NPP instance, NPStream *stream, int32 offset,
592                  int32 len, void *buffer )
593 {
594     /* TODO */
595     return len;
596 }
597
598 NPError NPP_DestroyStream( NPP instance, NPStream *stream, NPError reason )
599 {
600     if( instance == NULL )
601     {
602         return NPERR_INVALID_INSTANCE_ERROR;
603     }
604     return NPERR_NO_ERROR;
605 }
606
607 void NPP_StreamAsFile( NPP instance, NPStream *stream, const char* fname )
608 {
609     if( instance == NULL )
610     {
611         return;
612     }
613
614     VlcPlugin *p_plugin = reinterpret_cast<VlcPlugin *>(instance->pdata);
615     if( NULL == p_plugin )
616     {
617         return;
618     }
619
620     if( p_plugin->playlist_add( stream->url ) != -1 )
621     {
622         if( p_plugin->b_autoplay )
623         {
624             p_plugin->playlist_play();
625         }
626     }
627 }
628
629 void NPP_URLNotify( NPP instance, const char* url,
630                     NPReason reason, void* notifyData )
631 {
632     /***** Insert NPP_URLNotify code here *****\
633     PluginInstance* p_plugin;
634     if (instance != NULL)
635         p_plugin = (PluginInstance*) instance->pdata;
636     \*********************************************/
637 }
638
639 void NPP_Print( NPP instance, NPPrint* printInfo )
640 {
641     if( printInfo == NULL )
642     {
643         return;
644     }
645
646     if( instance != NULL )
647     {
648         /***** Insert NPP_Print code here *****\
649         PluginInstance* p_plugin = (PluginInstance*) instance->pdata;
650         \**************************************/
651
652         if( printInfo->mode == NP_FULL )
653         {
654             /*
655              * PLUGIN DEVELOPERS:
656              *  If your plugin would like to take over
657              *  printing completely when it is in full-screen mode,
658              *  set printInfo->pluginPrinted to TRUE and print your
659              *  plugin as you see fit.  If your plugin wants Netscape
660              *  to handle printing in this case, set
661              *  printInfo->pluginPrinted to FALSE (the default) and
662              *  do nothing.  If you do want to handle printing
663              *  yourself, printOne is true if the print button
664              *  (as opposed to the print menu) was clicked.
665              *  On the Macintosh, platformPrint is a THPrint; on
666              *  Windows, platformPrint is a structure
667              *  (defined in npapi.h) containing the printer name, port,
668              *  etc.
669              */
670
671             /***** Insert NPP_Print code here *****\
672             void* platformPrint =
673                 printInfo->print.fullPrint.platformPrint;
674             NPBool printOne =
675                 printInfo->print.fullPrint.printOne;
676             \**************************************/
677
678             /* Do the default*/
679             printInfo->print.fullPrint.pluginPrinted = FALSE;
680         }
681         else
682         {
683             /* If not fullscreen, we must be embedded */
684             /*
685              * PLUGIN DEVELOPERS:
686              *  If your plugin is embedded, or is full-screen
687              *  but you returned false in pluginPrinted above, NPP_Print
688              *  will be called with mode == NP_EMBED.  The NPWindow
689              *  in the printInfo gives the location and dimensions of
690              *  the embedded plugin on the printed page.  On the
691              *  Macintosh, platformPrint is the printer port; on
692              *  Windows, platformPrint is the handle to the printing
693              *  device context.
694              */
695
696             /***** Insert NPP_Print code here *****\
697             NPWindow* printWindow =
698                 &(printInfo->print.embedPrint.window);
699             void* platformPrint =
700                 printInfo->print.embedPrint.platformPrint;
701             \**************************************/
702         }
703     }
704 }
705
706 /******************************************************************************
707  * Windows-only methods
708  *****************************************************************************/
709 #if defined(XP_WIN)
710 static LRESULT CALLBACK Manage( HWND p_hwnd, UINT i_msg, WPARAM wpar, LPARAM lpar )
711 {
712     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(GetWindowLongPtr(p_hwnd, GWLP_USERDATA));
713
714     switch( i_msg )
715     {
716         case WM_ERASEBKGND:
717             return 1L;
718
719         case WM_PAINT:
720         {
721             PAINTSTRUCT paintstruct;
722             HDC hdc;
723             RECT rect;
724
725             hdc = BeginPaint( p_hwnd, &paintstruct );
726
727             GetClientRect( p_hwnd, &rect );
728
729             FillRect( hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH) );
730             SetTextColor(hdc, RGB(255, 255, 255));
731             SetBkColor(hdc, RGB(0, 0, 0));
732             if( p_plugin->psz_text )
733                 DrawText( hdc, p_plugin->psz_text, strlen(p_plugin->psz_text), &rect,
734                           DT_CENTER|DT_VCENTER|DT_SINGLELINE);
735
736             EndPaint( p_hwnd, &paintstruct );
737             return 0L;
738         }
739         default:
740             /* delegate to default handler */
741             return CallWindowProc( p_plugin->getWindowProc(), p_hwnd,
742                                    i_msg, wpar, lpar );
743     }
744 }
745 #endif /* XP_WIN */
746
747 /******************************************************************************
748  * UNIX-only methods
749  *****************************************************************************/
750 #if defined(XP_UNIX)
751 static void Redraw( Widget w, XtPointer closure, XEvent *event )
752 {
753     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(closure);
754     Window control = p_plugin->getControlWindow();
755     const NPWindow& window = p_plugin->getWindow();
756     GC gc;
757     XGCValues gcv;
758     unsigned int i_control_height, i_control_width;
759
760     if( p_plugin->b_toolbar )
761         p_plugin->getToolbarSize( &i_control_width, &i_control_height );
762     else
763         i_control_height = i_control_width = 0;
764
765     Window video = p_plugin->getVideoWindow();
766     Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
767
768     gcv.foreground = BlackPixel( p_display, 0 );
769     gc = XCreateGC( p_display, video, GCForeground, &gcv );
770
771     XFillRectangle( p_display, video, gc,
772                     0, 0, window.width, window.height - i_control_height);
773
774     gcv.foreground = WhitePixel( p_display, 0 );
775     XChangeGC( p_display, gc, GCForeground, &gcv );
776
777     if( p_plugin->psz_text )
778         XDrawString( p_display, video, gc,
779                      window.width / 2 - 40, (window.height - i_control_height) / 2,
780                      p_plugin->psz_text, strlen(p_plugin->psz_text) );
781     XFreeGC( p_display, gc );
782
783     p_plugin->redrawToolbar();
784 }
785
786 static void ControlHandler( Widget w, XtPointer closure, XEvent *event )
787 {
788     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(closure);
789     const NPWindow& window = p_plugin->getWindow();
790
791     int i_height = window.height;
792     int i_width = window.width;
793     int i_xPos = event->xbutton.x;
794     int i_yPos = event->xbutton.y;
795
796     if( p_plugin && p_plugin->b_toolbar )
797     {
798         int i_playing;
799
800         libvlc_media_player_t *p_md = p_plugin->getMD();
801
802         i_playing = p_plugin->playlist_isplaying();
803
804         vlc_toolbar_clicked_t clicked;
805         clicked = p_plugin->getToolbarButtonClicked( i_xPos, i_yPos );
806         switch( clicked )
807         {
808             case clicked_Play:
809             case clicked_Pause:
810             {
811                 if( i_playing == 1 )
812                     p_plugin->playlist_pause();
813                 else
814                     p_plugin->playlist_play();
815             }
816             break;
817
818             case clicked_Stop:
819             {
820                 p_plugin->playlist_stop();
821             }
822             break;
823
824             case clicked_Fullscreen:
825             {
826                 p_plugin->set_fullscreen( 1 );
827             }
828             break;
829
830             case clicked_Mute:
831             case clicked_Unmute:
832             {
833                 if( p_md )
834                     libvlc_audio_toggle_mute( p_md );
835             }
836             break;
837
838             case clicked_timeline:
839             {
840                 /* if a movie is loaded */
841                 if( p_md )
842                 {
843                     int64_t f_length;
844                     f_length = libvlc_media_player_get_length( p_md ) / 100;
845
846                     f_length = (float)f_length *
847                             ( ((float)i_xPos-4.0 ) / ( ((float)i_width-8.0)/100) );
848
849                     libvlc_media_player_set_time( p_md, f_length );
850                 }
851             }
852             break;
853
854             case clicked_Time:
855             {
856                 /* Not implemented yet*/
857             }
858             break;
859
860             default: /* button_Unknown */
861             break;
862         }
863     }
864     Redraw( w, closure, event );
865 }
866
867 static void Resize ( Widget w, XtPointer closure, XEvent *event )
868 {
869     VlcPlugin* p_plugin = reinterpret_cast<VlcPlugin*>(closure);
870     Window control = p_plugin->getControlWindow();
871     const NPWindow& window = p_plugin->getWindow();
872     Window  drawable   = p_plugin->getVideoWindow();
873     Display *p_display = ((NPSetWindowCallbackStruct *)window.ws_info)->display;
874
875     int i_ret;
876     Window root_return, parent_return, * children_return;
877     Window base_window;
878     unsigned int i_nchildren;
879     unsigned int i_control_height, i_control_width;
880
881     if( p_plugin->b_toolbar )
882     {
883         p_plugin->getToolbarSize( &i_control_width, &i_control_height );
884     }
885     else
886     {
887         i_control_height = i_control_width = 0;
888     }
889
890 #ifdef X11_RESIZE_DEBUG
891     XWindowAttributes attr;
892
893     if( event && event->type == ConfigureNotify )
894     {
895         fprintf( stderr, "vlcshell::Resize() ConfigureNotify %d x %d, "
896                  "send_event ? %s\n", event->xconfigure.width,
897                  event->xconfigure.height,
898                  event->xconfigure.send_event ? "TRUE" : "FALSE" );
899     }
900 #endif /* X11_RESIZE_DEBUG */
901
902     if( ! p_plugin->setSize(window.width, (window.height - i_control_height)) )
903     {
904         /* size already set */
905         return;
906     }
907
908     i_ret = XResizeWindow( p_display, drawable,
909                            window.width, (window.height - i_control_height) );
910
911 #ifdef X11_RESIZE_DEBUG
912     fprintf( stderr,
913              "vlcshell::Resize() XResizeWindow(owner) returned %d\n", i_ret );
914
915     XGetWindowAttributes ( p_display, drawable, &attr );
916
917     /* X is asynchronous, so the current size reported here is not
918        necessarily the requested size as the Resize request may not
919        yet have been handled by the plugin host */
920     fprintf( stderr, "vlcshell::Resize() current (owner) size %d x %d\n",
921              attr.width, attr.height );
922 #endif /* X11_RESIZE_DEBUG */
923
924     XQueryTree( p_display, drawable,
925                 &root_return, &parent_return, &children_return,
926                 &i_nchildren );
927
928     if( i_nchildren > 0 )
929     {
930         /* XXX: Make assumptions related to the window parenting structure in
931            vlc/modules/video_output/x11/xcommon.c */
932         base_window = children_return[i_nchildren - 1];
933
934 #ifdef X11_RESIZE_DEBUG
935         fprintf( stderr, "vlcshell::Resize() got %d children\n", i_nchildren );
936         fprintf( stderr, "vlcshell::Resize() got base_window %p\n",
937                  base_window );
938 #endif /* X11_RESIZE_DEBUG */
939
940         i_ret = XResizeWindow( p_display, base_window,
941                 window.width, ( window.height - i_control_height ) );
942
943 #ifdef X11_RESIZE_DEBUG
944         fprintf( stderr,
945                  "vlcshell::Resize() XResizeWindow(base) returned %d\n",
946                  i_ret );
947
948         XGetWindowAttributes( p_display, base_window, &attr );
949
950         fprintf( stderr, "vlcshell::Resize() new size %d x %d\n",
951                  attr.width, attr.height );
952 #endif /* X11_RESIZE_DEBUG */
953     }
954 }
955
956 #endif /* XP_UNIX */