Add default constructor to wxGraphicsGradientStop.
[wxWidgets.git] / src / unix / mediactrl.cpp
index b461f9d96571f3d60c154370de0e036ca644a2b5..0fbf87aa14144c8263200295b2510c3e9ea1b9ef 100644 (file)
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
-#include "wx/mediactrl.h"
-
 #if wxUSE_MEDIACTRL
 
+#include "wx/mediactrl.h"
+
 #if wxUSE_GSTREAMER
 
 #include <gst/gst.h>                // main gstreamer header
 #   include <gst/gconf/gconf.h>        // gstreamer glib configuration
 #endif
 
-#include "wx/log.h"                 // wxLogDebug/wxLogSysError/wxLogTrace
-#include "wx/app.h"                 // wxTheApp->argc, wxTheApp->argv
+#ifndef  WX_PRECOMP
+    #include "wx/log.h"             // wxLogDebug/wxLogSysError/wxLogTrace
+    #include "wx/app.h"             // wxTheApp->argc, wxTheApp->argv
+    #include "wx/timer.h"           // wxTimer
+#endif
+
 #include "wx/thread.h"              // wxMutex/wxMutexLocker
-#include "wx/timer.h"               // wxTimer
 
 #ifdef __WXGTK__
-#    include "wx/gtk/win_gtk.h"     // for <gdk/gdkx.h>/GDK_WINDOW_XWINDOW
+    #include <gtk/gtk.h>
+#    include <gdk/gdkx.h>           // for GDK_WINDOW_XWINDOW
 #endif
 
 //-----------------------------------------------------------------------------
 // Max wait time for element state waiting - GST_CLOCK_TIME_NONE for inf
 #define wxGSTREAMER_TIMEOUT (100 * GST_MSECOND) // Max 100 milliseconds
 
-//-----------------------------------------------------------------------------
-// wxGTK Debugging and idle stuff
-//-----------------------------------------------------------------------------
-#ifdef __WXGTK__
-
-#   ifdef __WXDEBUG__
-#       if wxUSE_THREADS
-#           define DEBUG_MAIN_THREAD \
-                if (wxThread::IsMain() && g_mainThreadLocked) \
-                    wxPrintf(wxT("gui reentrance"));
-#       else
-#           define DEBUG_MAIN_THREAD
-#       endif
-#   else
-#      define DEBUG_MAIN_THREAD
-#   endif // Debug
-
-extern void wxapp_install_idle_handler();
-extern bool g_isIdle;
-extern bool g_mainThreadLocked;
-#endif // wxGTK
-
 //-----------------------------------------------------------------------------
 //  wxLogTrace mask string
 //-----------------------------------------------------------------------------
@@ -162,7 +144,7 @@ class WXDLLIMPEXP_MEDIA
 public:
 
     wxGStreamerMediaBackend();
-    ~wxGStreamerMediaBackend();
+    virtual ~wxGStreamerMediaBackend();
 
     virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
                                      wxWindowID id,
@@ -178,6 +160,10 @@ public:
 
     virtual bool Load(const wxString& fileName);
     virtual bool Load(const wxURI& location);
+    virtual bool Load(const wxURI& location,
+                      const wxURI& proxy)
+        { return wxMediaBackendCommonBase::Load(location, proxy); }
+
 
     virtual wxMediaState GetState();
 
@@ -198,6 +184,7 @@ public:
     virtual double GetVolume();
 
     //------------implementation from now on-----------------------------------
+    bool DoLoad(const wxString& locstring);
     wxMediaCtrl* GetControl() { return m_ctrl; } // for C Callbacks
     void HandleStateChange(GstElementState oldstate, GstElementState newstate);
     bool QueryVideoSizeFromElement(GstElement* element);
@@ -275,7 +262,7 @@ static gboolean gtk_window_expose_callback(GtkWidget *widget,
     if(event->count > 0)
         return FALSE;
 
-    GdkWindow *window = GTK_PIZZA(be->GetControl()->m_wxwindow)->bin_window;
+    GdkWindow *window = widget->window;
 
     // I've seen this reccommended somewhere...
     // TODO: Is this needed? Maybe it is just cruft...
@@ -313,18 +300,12 @@ static gboolean gtk_window_expose_callback(GtkWidget *widget,
 //-----------------------------------------------------------------------------
 #ifdef __WXGTK__
 extern "C" {
-static gint gtk_window_realize_callback(GtkWidget* theWidget,
+static gint gtk_window_realize_callback(GtkWidget* widget,
                                         wxGStreamerMediaBackend* be)
 {
-    DEBUG_MAIN_THREAD // TODO: Is this neccessary?
-
-    if (g_isIdle)   // FIXME: Why is needed? For wxYield? ??
-        wxapp_install_idle_handler();
+    gdk_flush();
 
-    wxYield();    // FIXME: RN: X Server gets an error/crash if I don't do
-                  //       this or a messagebox beforehand?!?!??
-
-    GdkWindow *window = GTK_PIZZA(theWidget)->bin_window;
+    GdkWindow *window = widget->window;
     wxASSERT(window);
 
     gst_x_overlay_set_xwindow_id( GST_X_OVERLAY(be->m_xoverlay),
@@ -368,7 +349,7 @@ static void gst_state_change_callback(GstElement *play,
 // Called by gstreamer when the media is done playing ("end of stream")
 //-----------------------------------------------------------------------------
 extern "C" {
-static void gst_finish_callback(GstElement *play,
+static void gst_finish_callback(GstElement *WXUNUSED(play),
                                 wxGStreamerMediaBackend* be)
 {
     wxLogTrace(wxTRACE_GStreamer, wxT("gst_finish_callback"));
@@ -385,11 +366,11 @@ static void gst_finish_callback(GstElement *play,
 // on the command line as well for those who want extra traces.
 //-----------------------------------------------------------------------------
 extern "C" {
-static void gst_error_callback(GstElement *play,
-                               GstElement *src,
+static void gst_error_callback(GstElement *WXUNUSED(play),
+                               GstElement *WXUNUSED(src),
                                GError     *err,
                                gchar      *debug,
-                               wxGStreamerMediaBackend* be)
+                               wxGStreamerMediaBackend* WXUNUSED(be))
 {
     wxString sError;
     sError.Printf(wxT("gst_error_callback\n")
@@ -411,7 +392,7 @@ static void gst_error_callback(GstElement *play,
 //-----------------------------------------------------------------------------
 extern "C" {
 static void gst_notify_caps_callback(GstPad* pad,
-                                     GParamSpec* pspec,
+                                     GParamSpec* WXUNUSED(pspec),
                                      wxGStreamerMediaBackend* be)
 {
     wxLogTrace(wxTRACE_GStreamer, wxT("gst_notify_caps_callback"));
@@ -433,8 +414,8 @@ static void gst_notify_caps_callback(GstPad* pad,
 //-----------------------------------------------------------------------------
 #if GST_VERSION_MAJOR > 0 || GST_VERSION_MINOR >= 10
 extern "C" {
-static void gst_notify_stream_info_callback(GstElement* element,
-                                            GParamSpec* pspec,
+static void gst_notify_stream_info_callback(GstElement* WXUNUSED(element),
+                                            GParamSpec* WXUNUSED(pspec),
                                             wxGStreamerMediaBackend* be)
 {
     wxLogTrace(wxTRACE_GStreamer, wxT("gst_notify_stream_info_callback"));
@@ -484,7 +465,7 @@ static void gst_desired_size_changed_callback(GstElement * play,
 //-----------------------------------------------------------------------------
 #if GST_VERSION_MAJOR > 0 || GST_VERSION_MINOR >= 10
 extern "C" {
-static gboolean gst_bus_async_callback(GstBus* bus,
+static gboolean gst_bus_async_callback(GstBus* WXUNUSED(bus),
                                        GstMessage* message,
                                        wxGStreamerMediaBackend* be)
 {
@@ -727,8 +708,9 @@ void wxGStreamerMediaBackend::SetupXOverlay()
     }
     else
     {
-        wxYield(); // see realize callback...
-        GdkWindow *window = GTK_PIZZA(m_ctrl->m_wxwindow)->bin_window;
+        gdk_flush();
+
+        GdkWindow *window = m_ctrl->m_wxwindow->window;
         wxASSERT(window);
 #endif
 
@@ -908,7 +890,7 @@ bool wxGStreamerMediaBackend::TryVideoSink(GstElement* videosink)
 //
 // Called when the media is about to stop
 //-----------------------------------------------------------------------------
-void wxGStreamerMediaEventHandler::OnMediaFinish(wxMediaEvent& event)
+void wxGStreamerMediaEventHandler::OnMediaFinish(wxMediaEvent& WXUNUSED(event))
 {
     // (RN - I have no idea why I thought this was good behaviour....
     // maybe it made sense for streaming/nonseeking data but
@@ -950,7 +932,8 @@ void wxGStreamerMediaEventHandler::OnMediaFinish(wxMediaEvent& event)
 // Sets m_playbin to NULL signifying we havn't loaded anything yet
 //-----------------------------------------------------------------------------
 wxGStreamerMediaBackend::wxGStreamerMediaBackend()
-    : m_playbin(NULL)
+    : m_playbin(NULL),
+      m_eventHandler(NULL)
 {
 }
 
@@ -990,7 +973,62 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
     //
     //init gstreamer
     //
-    gst_init(&wxTheApp->argc, &wxTheApp->argv);
+
+    //Convert arguments to unicode if enabled
+#if wxUSE_UNICODE
+    int i;
+    char **argvGST = new char*[wxTheApp->argc + 1];
+    for ( i = 0; i < wxTheApp->argc; i++ )
+    {
+#if wxUSE_UNICODE_WCHAR
+        argvGST[i] = wxStrdupA(wxConvUTF8.cWX2MB(wxTheApp->argv[i]));
+#else
+        argvGST[i] = wxStrdupA(wxTheApp->argv[i].utf8_str());
+#endif
+    }
+
+    argvGST[wxTheApp->argc] = NULL;
+
+    int argcGST = wxTheApp->argc;
+#else
+#define argcGST wxTheApp->argc
+#define argvGST wxTheApp->argv
+#endif
+
+    //Really init gstreamer
+    gboolean bInited;
+    GError* error = NULL;
+#if GST_VERSION_MAJOR > 0 || GST_VERSION_MINOR >= 10
+    bInited = gst_init_check(&argcGST, &argvGST, &error);
+#else
+    bInited = gst_init_check(&argcGST, &argvGST);
+#endif
+
+    // Cleanup arguments for unicode case
+#if wxUSE_UNICODE
+    for ( i = 0; i < argcGST; i++ )
+    {
+        free(argvGST[i]);
+    }
+
+    delete [] argvGST;
+#endif
+
+    if(!bInited)    //gst_init_check fail?
+    {
+        if(error)
+        {
+            wxLogSysError(wxT("Could not initialize GStreamer\n")
+                          wxT("Error Message:%s"),
+                          (const wxChar*) wxConvUTF8.cMB2WX(error->message)
+                         );
+            g_error_free(error);
+        }
+        else
+            wxLogSysError(wxT("Could not initialize GStreamer"));
+
+        return false;
+    }
 
     //
     // wxControl creation
@@ -999,7 +1037,7 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
 
 #ifdef __WXGTK__
     // We handle our own GTK expose events
-    m_ctrl->m_noExpose = TRUE;
+    m_ctrl->m_noExpose = true;
 #endif
 
     if( !m_ctrl->wxControl::Create(parent, id, pos, size,
@@ -1015,9 +1053,6 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
     // so it doesn't draw over the video and cause sporadic
     // disappearances of the video
     gtk_widget_set_double_buffered(m_ctrl->m_wxwindow, FALSE);
-
-    // Tell GtkPizza not to clear the background
-    gtk_pizza_set_clear(GTK_PIZZA(m_ctrl->m_wxwindow), FALSE);
 #endif
 
     // don't erase the background of our control window
@@ -1027,12 +1062,12 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
     // Create our playbin object
     m_playbin = gst_element_factory_make ("playbin", "play");
     if (!GST_IS_ELEMENT(m_playbin))
-        {
+    {
         if(G_IS_OBJECT(m_playbin))
             g_object_unref(m_playbin);
         wxLogSysError(wxT("Got an invalid playbin"));
         return false;
-        }
+    }
 
 #if GST_VERSION_MAJOR == 0 && GST_VERSION_MINOR < 10
     // Connect the glib events/callbacks we want to our playbin
@@ -1068,7 +1103,7 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                 if( !TryAudioSink(audiosink) )
                 {
                     wxLogSysError(wxT("Could not find a valid audiosink"));
-    return false;
+                    return false;
                 }
             }
         }
@@ -1093,7 +1128,7 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                     g_object_unref(audiosink);
                     wxLogSysError(wxT("Could not find a suitable video sink"));
                     return false;
-    }
+                }
             }
         }
     }
@@ -1121,20 +1156,40 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
 //-----------------------------------------------------------------------------
 // wxGStreamerMediaBackend::Load (File version)
 //
-// Just calls the URI version
+// Just calls DoLoad() with a prepended file scheme
 //-----------------------------------------------------------------------------
 bool wxGStreamerMediaBackend::Load(const wxString& fileName)
 {
-    return Load(
-                    wxURI(
-                            wxString( wxT("file://") ) + fileName
-                         )
-               );
+    return DoLoad(wxString( wxT("file://") ) + fileName);
 }
 
 //-----------------------------------------------------------------------------
 // wxGStreamerMediaBackend::Load (URI version)
 //
+// In the case of a file URI passes it unencoded -
+// also, as of 0.10.3 and earlier GstURI (the uri parser for gstreamer)
+// is sort of broken and only accepts uris with at least two slashes
+// after the scheme (i.e. file: == not ok, file:// == ok)
+//-----------------------------------------------------------------------------
+bool wxGStreamerMediaBackend::Load(const wxURI& location)
+{
+    if(location.GetScheme().CmpNoCase(wxT("file")) == 0)
+    {
+        wxString uristring = location.BuildUnescapedURI();
+
+        //Workaround GstURI leading "//" problem and make sure it leads
+        //with that
+        return DoLoad(wxString(wxT("file://")) +
+                      uristring.Right(uristring.length() - 5)
+                     );
+    }
+    else
+        return DoLoad(location.BuildURI());
+}
+
+//-----------------------------------------------------------------------------
+// wxGStreamerMediaBackend::DoLoad
+//
 // Loads the media
 // 1) Reset member variables and set playbin back to ready state
 // 2) Check URI for validity and then tell the playbin to load it
@@ -1144,7 +1199,7 @@ bool wxGStreamerMediaBackend::Load(const wxString& fileName)
 // video size or duration - no amount of clever hacking is going to get
 // around that, unfortunately.
 //-----------------------------------------------------------------------------
-bool wxGStreamerMediaBackend::Load(const wxURI& location)
+bool wxGStreamerMediaBackend::DoLoad(const wxString& locstring)
 {
     wxMutexLocker lock(m_asynclock); // lock state events and async callbacks
 
@@ -1163,14 +1218,11 @@ bool wxGStreamerMediaBackend::Load(const wxURI& location)
             return false;
     }
 
+    // free current media resources
+    gst_element_set_state (m_playbin, GST_STATE_NULL);
+
     // Make sure the passed URI is valid and tell playbin to load it
     // non-file uris are encoded
-    wxString locstring;
-    if(location.GetScheme().CmpNoCase(wxT("file")))
-        locstring = location.BuildUnescapedURI();
-    else
-        locstring = location.BuildURI();
-
     wxASSERT(gst_uri_protocol_is_valid("file"));
     wxASSERT(gst_uri_is_valid(locstring.mb_str()));
 
@@ -1291,7 +1343,7 @@ wxMediaState wxGStreamerMediaBackend::GetState()
 // NB: whether we have paused or not and keep track of the time after the
 // NB: pause and whenever the user seeks while paused
 // NB:
-// 
+//
 // THREAD-UNSAFE, at least if not paused. Requires media to be at least paused.
 //-----------------------------------------------------------------------------
 wxLongLong wxGStreamerMediaBackend::GetPosition()
@@ -1385,7 +1437,10 @@ wxLongLong wxGStreamerMediaBackend::GetDuration()
 // Called when the window is moved - GStreamer takes care of this
 // for us so nothing is needed
 //-----------------------------------------------------------------------------
-void wxGStreamerMediaBackend::Move(int x, int y, int w, int h)
+void wxGStreamerMediaBackend::Move(int WXUNUSED(x),
+                                   int WXUNUSED(y),
+                                   int WXUNUSED(w),
+                                   int WXUNUSED(h))
 {
 }
 
@@ -1443,6 +1498,8 @@ bool wxGStreamerMediaBackend::SetPlaybackRate(double dRate)
         m_dRate = dRate;
         return true;
     }
+#else
+    wxUnusedVar(dRate);
 #endif
 #endif