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