]> git.sesse.net Git - vlc/commitdiff
* modules/control/corba/: Olivier Aubert's CORBA plugin. Almost verbatim,
authorSam Hocevar <sam@videolan.org>
Mon, 7 Jul 2003 16:59:00 +0000 (16:59 +0000)
committerSam Hocevar <sam@videolan.org>
Mon, 7 Jul 2003 16:59:00 +0000 (16:59 +0000)
    compiles cleanly (to build the medicacontrol.so library you need to cd to
    that directory and "make medicacontrol.so") but untested.
  * src/playlist/playlist.c: Mostly harmless fix to playlist.c suggested by
    Olivier.

12 files changed:
configure.ac
modules/control/corba/.cvsignore [new file with mode: 0644]
modules/control/corba/Modules.am [new file with mode: 0644]
modules/control/corba/README [new file with mode: 0644]
modules/control/corba/client.py [new file with mode: 0644]
modules/control/corba/corba.c [new file with mode: 0644]
modules/control/corba/launch-vlc-corba [new file with mode: 0644]
modules/control/corba/mediacontrol.idl [new file with mode: 0644]
modules/control/corba/pyorbit-1.99.3.patch [new file with mode: 0644]
modules/control/corba/simpleplayer.glade [new file with mode: 0644]
modules/control/corba/simpleplayer.py [new file with mode: 0644]
src/playlist/playlist.c

index f423f7ac972cf60303b25eb5b700add86ac60ead..9abbd4c014da3cd637c9449157b8a02d2d0f597f 100644 (file)
@@ -1,5 +1,5 @@
 dnl Autoconf settings for vlc
-dnl $Id: configure.ac,v 1.26 2003/07/07 14:56:22 massiot Exp $
+dnl $Id: configure.ac,v 1.27 2003/07/07 16:59:00 sam Exp $
 
 AC_INIT(vlc,0.6.0)
 
@@ -2930,6 +2930,37 @@ then
   fi
 fi
 
+dnl
+dnl corba (ORBit) plugin
+dnl
+AC_ARG_ENABLE(corba,
+  [  --enable-corba          corba interface support (default disabled)])
+if test "${enable_corba}" = "yes"; then
+  ORBIT_PATH="${PATH}"
+  AC_ARG_WITH(orbit-config-path,
+  [    --with-orbit-config-path=PATH orbit-config path (default search in \$PATH)])
+  if test "${with_orbit_config_path}" != "no"; then
+    ORBIT_PATH="${with_orbit_config_path}:${PATH}"
+  fi
+  # look for orbit2-config
+  AC_PATH_PROG(ORBIT_CONFIG, orbit2-config, no, ${ORBIT_PATH})
+  if test "${ORBIT_CONFIG}" != "no"; then
+    AX_ADD_CFLAGS(corba,[`${ORBIT_CONFIG} --cflags server`])
+    AX_ADD_LDFLAGS(corba,[`${ORBIT_CONFIG} --libs server | sed 's,-rdynamic,,'`])
+    # now look for the orbit.h header
+    CPPFLAGS="${CPPFLAGS_save} ${CFLAGS_corba}"
+    ac_cv_corba_headers=yes
+    AC_CHECK_HEADERS(orbit/orbit.h, , [
+      ac_cv_corba_headers=no
+      AC_MSG_ERROR([Could not find corba development headers])
+    ])
+    if test "${ac_cv_corba_headers}" = "yes"; then
+      AX_ADD_PLUGINS(corba)
+    fi
+    CPPFLAGS="${CPPFLAGS_save}"
+  fi
+fi
+
 AC_ARG_WITH(,[Misc options:])
 
 dnl
@@ -3237,6 +3268,7 @@ AC_OUTPUT([
   modules/codec/mpeg_video/motion/Makefile
   modules/codec/spudec/Makefile
   modules/control/Makefile
+  modules/control/corba/Makefile
   modules/control/lirc/Makefile
   modules/control/rc/Makefile
   modules/demux/Makefile
diff --git a/modules/control/corba/.cvsignore b/modules/control/corba/.cvsignore
new file mode 100644 (file)
index 0000000..c930ed7
--- /dev/null
@@ -0,0 +1,11 @@
+.deps
+.dirstamp
+*.lo
+*.la
+*.dll
+*.dylib
+*.sl
+*.so
+Makefile.am
+Makefile.in
+Makefile
diff --git a/modules/control/corba/Modules.am b/modules/control/corba/Modules.am
new file mode 100644 (file)
index 0000000..fe80bff
--- /dev/null
@@ -0,0 +1,25 @@
+## corba module declaration
+
+SOURCES_corba = corba.c
+
+nodist_SOURCES_corba = \
+       mediacontrol-common.c \
+       mediacontrol-skels.c \
+       mediacontrol.h \
+       $(NULL)
+
+ORBITIDL = orbit-idl-2
+
+mediacontrol-common.c mediacontrol-skels.c mediacontrol-stubs.c mediacontrol.h:
+       $(ORBITIDL) --skeleton-impl mediacontrol.idl
+
+mediacontrol-imodule.c:
+       $(ORBITIDL) --imodule mediacontrol.idl
+
+mediacontrol.so: mediacontrol-imodule.c
+       gcc -fPIC -o mediacontrol-imodule.o -c mediacontrol-imodule.c `pkg-config --cflags ORBit-2.0`
+       gcc -shared -o $@ mediacontrol-imodule.o `pkg-config --libs ORBit-2.0`
+
+clean:
+       rm -f mediacontrol-stubs.c mediacontrol-imodule.c mediacontrol-skelimpl.c
+
diff --git a/modules/control/corba/README b/modules/control/corba/README
new file mode 100644 (file)
index 0000000..aa99b49
--- /dev/null
@@ -0,0 +1,64 @@
+$Id: README,v 1.1 2003/07/07 16:59:00 sam Exp $
+* Module (server) side
+** Dependencies
+
+To compile the CORBA plugin, you need the orbit2 developpement files
+(for Debian, install the package liborbi2-dev)
+
+** How to run it ?
+
+You run the CORBA module  with the following command line :
+
+vlc --intf corba
+
+The CORBA module is initialized and saves its IOR into the file
+/tmp/vlc-ior.ref
+
+
+* Client side
+
+A sample client application is provided, using python-orbit
+
+**  Dependencies
+
+The python client uses the pyorbit library developped by James
+Henstridge <james at daa dot com dot au> (source:
+http://ftp.gnome.org/pub/GNOME/sources/pyorbit/1.99/pyorbit-1.99.3.tar.gz).
+
+To interoperate with gtk, the original pyorbit-1.99.3 needs a patch to
+implement the bindings to OR_work_pending and ORB_perform_work (see
+pyorbit-1.99.3.patch)
+
+The gtk simpleplayer example uses the python-glade module by James
+Henstridge.
+
+** Typelib information
+
+To simply access the server, you do not need any reference to the IDL
+(CORBA2.0 provides introspection facilities). However, if you want to
+use the structures defined in the IDL (Position, Origin, ...), you
+need to use the IDL information, and compile a dynamic lib
+(MediaControl.so) from the IDL.
+
+To build the library, you can use the Makefile :
+
+make corba-generate-typelib
+
+which will generate MediaControl.so
+
+* Interesting pointers 
+
+- GLib reference manual
+http://developer.gnome.org/doc/API/glib/
+
+- IDL quickref :
+http://www.cs.rpi.edu/~musser/dsc/idl/idl-overview.html
+
+- Python-Bonobo
+http://www.pycage.de/howto_bonobo.html
+
+* How to add the module to the original sources (vlc-0.5.x) :
+- copy the directory modules/control/corba
+- add configuration lines relative to corba in configure.ac.in
+- add a reference to  control/corba/Modules.am in
+  modules/Makefile.am
diff --git a/modules/control/corba/client.py b/modules/control/corba/client.py
new file mode 100644 (file)
index 0000000..d23006c
--- /dev/null
@@ -0,0 +1,34 @@
+#! /usr/bin/python
+
+# Simple CLI client for the corba module of vlc. Depends on pyorbit.
+# Best used with IPython (completion, ...)
+
+import sys
+import ORBit, CORBA
+
+def quit ():
+       try:
+               mc.exit()
+       except:
+               pass
+               
+print "Chargement de l'IDL"
+ORBit.load_typelib ("./MediaControl.so")
+import VLC
+
+if len(sys.argv) < 1:
+       print "Usage: %s" % sys.argv[0]
+       sys.exit(1)
+
+print "Initialisation de l'ORB"
+orb = CORBA.ORB_init()
+
+ior = open("/tmp/vlc-ior.ref").readline()
+mc = orb.string_to_object(ior)
+
+print "Objet mc %s" % mc
+
+pos = mc.get_media_position (0,0)
+print "pos = mc.get_media_position (0,0)"
+print pos
+
diff --git a/modules/control/corba/corba.c b/modules/control/corba/corba.c
new file mode 100644 (file)
index 0000000..4288183
--- /dev/null
@@ -0,0 +1,861 @@
+/*****************************************************************************
+ * corba.c : CORBA (ORBit) remote control plugin for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: corba.c,v 1.1 2003/07/07 16:59:00 sam Exp $
+ *
+ * Authors: Olivier Aubert <oaubert at lisi dot univ-lyon1 dot fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+/* For CORBA */
+#include "mediacontrol.h"
+#include "orbit/poa/portableserver-poa-type.h"
+#define VLC_IOR_FILE "/tmp/vlc-ior.ref"
+
+#define handle_exception(m) if(ev->_major != CORBA_NO_EXCEPTION) \
+    { \
+      msg_Err (servant->p_intf, m); \
+      return; \
+    }
+
+
+#define handle_exception_no_servant(p,m) if(ev->_major != CORBA_NO_EXCEPTION) \
+    { \
+      msg_Err (p, m); \
+      return; \
+    }
+
+#include <vlc/vlc.h>
+#include <vlc/intf.h>
+#include <vlc/vout.h>
+#include <vlc/aout.h>
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
+
+#include <errno.h>                                                 /* ENOMEM */
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#    include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#endif
+#include <sys/types.h>
+
+/*****************************************************************************
+ * intf_sys_t: description and status of corba interface
+ *****************************************************************************/
+struct intf_sys_t
+{
+  CORBA_ORB                 orb;
+  VLC_MediaControl          mc;
+  PortableServer_POA        root_poa;
+  PortableServer_POAManager root_poa_manager;
+  GMainLoop*                corbaloop;
+
+  vlc_bool_t          b_playing;
+
+  input_thread_t *    p_input;                /* The input thread */
+
+  msg_subscription_t* p_sub;                  /* message bank subscription */
+};
+
+/* Convert an offset into seconds. Taken from input_ext-intf.c.
+   The 50 hardcoded constant comes from the definition of i_mux_rate :
+   i_mux_rate : the rate we read the stream (in units of 50 bytes/s) ;
+   0 if undef */
+long long offsetToSeconds (input_thread_t *p_input, off_t l_offset)
+{
+  long long l_res;
+
+  l_res = -1;
+  if (p_input != NULL && p_input->stream.i_mux_rate != 0)
+    {
+      l_res = (long long) l_offset / 50 / p_input->stream.i_mux_rate;
+    }
+  return l_res;
+}
+
+/* Convert an offset into milliseconds */
+long long offsetToMilliseconds (input_thread_t *p_input, off_t l_offset)
+{
+  long long l_res;
+
+  l_res = -1;
+  if (p_input != NULL && p_input->stream.i_mux_rate != 0)
+    {
+      l_res = (long long) 1000 * l_offset / 50 / p_input->stream.i_mux_rate;
+    }
+  return l_res;
+}
+
+/* Convert seconds to an offset */
+off_t secondsToOffset (input_thread_t *p_input, long long l_seconds)
+{
+  off_t l_res;
+
+  l_res = -1;
+
+  if (p_input != NULL)
+    {
+      l_res = (off_t) l_seconds * 50 * p_input->stream.i_mux_rate;
+    }
+  return l_res;
+}
+
+
+/* Convert milliseconds to an offset */
+off_t millisecondsToOffset (input_thread_t *p_input, long long l_milliseconds)
+{
+  off_t l_res;
+
+  l_res = -1;
+  if (p_input != NULL)
+    {
+      l_res = (off_t) l_milliseconds * 50 * p_input->stream.i_mux_rate / 1000;
+    }
+  return l_res;
+}
+
+/* Returns the current offset. */
+off_t currentOffset (input_thread_t *p_input)
+{
+  off_t l_offset;
+
+  if( p_input == NULL )
+    {
+      return -1;
+    }
+
+  /* offset contient la valeur en unités arbitraires (cf
+     include/input_ext-intf.h) */
+  vlc_mutex_lock( &p_input->stream.stream_lock );
+
+#define A p_input->stream.p_selected_area
+  l_offset = A->i_tell + A->i_start;
+#undef A
+  vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+  return l_offset;
+}
+
+/*** App-specific servant structures ***/
+
+/* We can add attributes to this structure, which is both a pointer on a
+   specific structure, and on a POA_VLC_MediaControl (servant). Cf
+   http://developer.gnome.org/doc/guides/corba/html/corba-poa-example.html */
+
+typedef struct
+{
+  POA_VLC_MediaControl servant;
+  PortableServer_POA poa;
+  /* Ajouter ici les attributs utiles */
+  intf_thread_t *p_intf;
+}
+impl_POA_VLC_MediaControl;
+
+/* Beginning of the CORBA code generated in Mediacontrol-skelimpl.c */
+/* BEGIN INSERT */
+
+/*** Implementation stub prototypes ***/
+
+static void impl_VLC_MediaControl__destroy(impl_POA_VLC_MediaControl *
+                                           servant, CORBA_Environment * ev);
+
+static VLC_Position
+impl_VLC_MediaControl_get_media_position(impl_POA_VLC_MediaControl * servant,
+                                         const VLC_PositionOrigin an_origin,
+                                         const VLC_PositionKey a_key,
+                                         CORBA_Environment * ev);
+
+static void
+impl_VLC_MediaControl_set_media_position(impl_POA_VLC_MediaControl * servant,
+                                         const VLC_Position * a_position,
+                                         CORBA_Environment * ev);
+
+static void
+impl_VLC_MediaControl_start(impl_POA_VLC_MediaControl * servant,
+                            const VLC_Position * a_position,
+                            CORBA_Environment * ev);
+
+static void
+impl_VLC_MediaControl_pause(impl_POA_VLC_MediaControl * servant,
+                            const VLC_Position * a_position,
+                            CORBA_Environment * ev);
+
+static void
+impl_VLC_MediaControl_resume(impl_POA_VLC_MediaControl * servant,
+                             const VLC_Position * a_position,
+                             CORBA_Environment * ev);
+
+static void
+impl_VLC_MediaControl_stop(impl_POA_VLC_MediaControl * servant,
+                           const VLC_Position * a_position,
+                           CORBA_Environment * ev);
+
+static void
+impl_VLC_MediaControl_exit(impl_POA_VLC_MediaControl * servant,
+                           CORBA_Environment * ev);
+
+static void
+impl_VLC_MediaControl_add_to_playlist(impl_POA_VLC_MediaControl * servant,
+                                      const CORBA_char * a_file,
+                                      CORBA_Environment * ev);
+
+static VLC_PlaylistSeq
+   *impl_VLC_MediaControl_get_playlist(impl_POA_VLC_MediaControl * servant,
+                                       CORBA_Environment * ev);
+
+/*** epv structures ***/
+
+static PortableServer_ServantBase__epv impl_VLC_MediaControl_base_epv = {
+   NULL,                        /* _private data */
+   NULL,                        /* finalize routine */
+   NULL,                        /* default_POA routine */
+};
+static POA_VLC_MediaControl__epv impl_VLC_MediaControl_epv = {
+   NULL,                        /* _private */
+
+   (gpointer) & impl_VLC_MediaControl_get_media_position,
+
+   (gpointer) & impl_VLC_MediaControl_set_media_position,
+
+   (gpointer) & impl_VLC_MediaControl_start,
+
+   (gpointer) & impl_VLC_MediaControl_pause,
+
+   (gpointer) & impl_VLC_MediaControl_resume,
+
+   (gpointer) & impl_VLC_MediaControl_stop,
+
+   (gpointer) & impl_VLC_MediaControl_exit,
+
+   (gpointer) & impl_VLC_MediaControl_add_to_playlist,
+
+   (gpointer) & impl_VLC_MediaControl_get_playlist,
+
+};
+
+/*** vepv structures ***/
+
+static POA_VLC_MediaControl__vepv impl_VLC_MediaControl_vepv = {
+   &impl_VLC_MediaControl_base_epv,
+   &impl_VLC_MediaControl_epv,
+};
+
+/*** Stub implementations ***/
+
+static VLC_MediaControl
+impl_VLC_MediaControl__create(PortableServer_POA poa, CORBA_Environment * ev)
+{
+   VLC_MediaControl retval;
+   impl_POA_VLC_MediaControl *newservant;
+   PortableServer_ObjectId *objid;
+
+   newservant = g_new0(impl_POA_VLC_MediaControl, 1);
+   newservant->servant.vepv = &impl_VLC_MediaControl_vepv;
+   newservant->poa = poa;
+   POA_VLC_MediaControl__init((PortableServer_Servant) newservant, ev);
+   objid = PortableServer_POA_activate_object(poa, newservant, ev);
+   CORBA_free(objid);
+   retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);
+
+   return retval;
+}
+
+static void
+impl_VLC_MediaControl__destroy(impl_POA_VLC_MediaControl * servant,
+                               CORBA_Environment * ev)
+{
+   PortableServer_ObjectId *objid;
+
+   objid = PortableServer_POA_servant_to_id(servant->poa, servant, ev);
+   PortableServer_POA_deactivate_object(servant->poa, objid, ev);
+   CORBA_free(objid);
+
+   POA_VLC_MediaControl__fini((PortableServer_Servant) servant, ev);
+   g_free(servant);
+}
+
+/* END INSERT */
+/* Beginning of the CORBA functions that we define */
+
+/* Returns the current position in the stream. The returned value can
+   be relative or absolute (according to PositionOrigin) and the unit
+   is set by PositionKey */
+static VLC_Position
+impl_VLC_MediaControl_get_media_position(impl_POA_VLC_MediaControl * servant,
+                                     const VLC_PositionOrigin an_origin,
+                                     const VLC_PositionKey a_key,
+                                     CORBA_Environment * ev)
+{
+  VLC_Position retval;
+  off_t l_offset;
+  VLC_PositionKeyNotSupported *exception;
+  input_thread_t * p_input = servant->p_intf->p_sys->p_input;
+
+  /*  msg_Warn (servant->p_intf, "Calling MediaControl::get_media_position"); */
+
+  retval.origin = an_origin;
+  retval.key = a_key;
+
+  if ( an_origin == VLC_RelativePosition
+       || an_origin == VLC_ModuloPosition )
+    {
+      /* Relative or ModuloPosition make no sense */
+      /* FIXME: should we return 0 or raise an exception ? */
+      retval.value = 0;
+      return retval;
+    }
+
+  if ( p_input == NULL )
+    {
+      /* FIXME: should we return 0 or raise an exception ? */
+      retval.value = 0;
+      return retval;
+    }
+
+  /* We are asked for an AbsolutePosition. */
+  /* Cf plugins/gtk/gtk_display.c */
+
+  /* The lock is taken by the currentOffset function */
+  l_offset = currentOffset (p_input);
+
+  if (a_key == VLC_ByteCount)
+    {
+      retval.value = l_offset;
+      return retval;
+    }
+  if (a_key == VLC_MediaTime)
+    {
+      retval.value = offsetToSeconds (p_input, l_offset);
+      return retval;
+    }
+  if (a_key == VLC_SampleCount)
+    {
+      /* Raising exceptions in C : cf the good explanations in
+         http://developer.gnome.org/doc/guides/corba/html/corba-module-complete-helloworld.html
+      */
+      exception = VLC_PositionKeyNotSupported__alloc ();
+      memcpy (&exception->key, &a_key, sizeof (a_key));
+      CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+                           ex_VLC_PositionKeyNotSupported,
+                           exception);
+      retval.value = 0;
+      return retval;
+    }
+
+  /* http://catb.org/~esr/jargon/html/entry/can't-happen.html */
+  return retval;
+}
+
+/* Sets the media position */
+static void
+impl_VLC_MediaControl_set_media_position(impl_POA_VLC_MediaControl * servant,
+                                         const VLC_Position * a_position,
+                                         CORBA_Environment * ev)
+{
+  VLC_InvalidPosition *pe_exception;
+  VLC_PositionKeyNotSupported *pe_key_exception;
+  off_t l_offset_destination = 0;
+  int i_whence = 0;
+  input_thread_t * p_input = servant->p_intf->p_sys->p_input;
+
+  msg_Warn (servant->p_intf, "Calling MediaControl::set_media_position");
+
+  if( p_input == NULL )
+      return;
+
+  if ( !p_input->stream.b_seekable )
+    {
+      pe_exception = VLC_InvalidPosition__alloc ();
+      memcpy (&pe_exception->key, &a_position->key, sizeof (&a_position->key));
+      CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+                           ex_VLC_InvalidPosition,
+                           pe_exception);
+      return;
+    }
+
+  switch ( a_position->key )
+    {
+    case VLC_SampleCount:
+      /* The SampleCount unit is still a bit mysterious... */
+      pe_key_exception = VLC_PositionKeyNotSupported__alloc ();
+      memcpy (&pe_key_exception->key, &a_position->key, sizeof (&a_position->key));
+      CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+                           ex_VLC_PositionKeyNotSupported,
+                           pe_key_exception);
+      return;
+      break;
+    case VLC_MediaTime:
+      i_whence |= INPUT_SEEK_SECONDS;
+      break;
+    case VLC_ByteCount:
+      i_whence |= INPUT_SEEK_BYTES;
+      break;
+    default:
+      i_whence |= INPUT_SEEK_BYTES;
+      break;
+    }
+
+  switch ( a_position->origin)
+    {
+    case VLC_RelativePosition:
+      i_whence |= INPUT_SEEK_CUR;
+      break;
+    case VLC_ModuloPosition:
+      i_whence |= INPUT_SEEK_END;
+      break;
+    case VLC_AbsolutePosition:
+      i_whence |= INPUT_SEEK_SET;
+      break;
+    default:
+      i_whence |= INPUT_SEEK_SET;
+      break;
+    }
+
+  l_offset_destination = a_position->value;
+
+  /* msg_Warn (servant->p_intf, "Offset destination : %d", l_offset_destination); */
+  /* Now we can set the position. The lock is taken in the input_Seek
+     function (cf input_ext-intf.c) */
+  input_Seek (p_input, l_offset_destination, i_whence);
+  return;
+}
+
+/* Starts playing a stream */
+static void
+impl_VLC_MediaControl_start(impl_POA_VLC_MediaControl * servant,
+                            const VLC_Position * a_position, CORBA_Environment * ev)
+{
+  intf_thread_t *  p_intf = servant->p_intf;
+  playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                             FIND_ANYWHERE );
+
+  msg_Warn (servant->p_intf, "Calling MediaControl::start");
+
+  if( p_playlist == NULL )
+    {
+      /* FIXME: we should raise an appropriate exception, but we must
+         define it in the IDL first */
+      msg_Err (servant->p_intf, "Error: no playlist available.");
+      return;
+    }
+
+    vlc_mutex_lock( &p_playlist->object_lock );
+    if( p_playlist->i_size )
+    {
+        vlc_mutex_unlock( &p_playlist->object_lock );
+        playlist_Play( p_playlist );
+        vlc_object_release( p_playlist );
+    }
+    else
+    {
+        vlc_mutex_unlock( &p_playlist->object_lock );
+        vlc_object_release( p_playlist );
+        msg_Err (servant->p_intf, "Error: playlist empty.");
+    }
+
+  return;
+}
+
+static void
+impl_VLC_MediaControl_pause(impl_POA_VLC_MediaControl * servant,
+                        const VLC_Position * a_position, CORBA_Environment * ev)
+{
+  input_thread_t *p_input = servant->p_intf->p_sys->p_input;
+
+  msg_Warn (servant->p_intf, "Calling MediaControl::pause");
+
+  if( p_input != NULL )
+    {
+      input_SetStatus( p_input, INPUT_STATUS_PAUSE );
+    }
+
+    return;
+}
+
+static void
+impl_VLC_MediaControl_resume(impl_POA_VLC_MediaControl * servant,
+                         const VLC_Position * a_position, CORBA_Environment * ev)
+{
+  input_thread_t *p_input = servant->p_intf->p_sys->p_input;
+
+  msg_Warn (servant->p_intf, "Calling MediaControl::resume");
+
+  if( p_input != NULL )
+    {
+      input_SetStatus( p_input, INPUT_STATUS_PAUSE );
+    }
+
+    return;
+}
+
+static void
+impl_VLC_MediaControl_stop(impl_POA_VLC_MediaControl * servant,
+                       const VLC_Position * a_position, CORBA_Environment * ev)
+{
+  intf_thread_t *  p_intf = servant->p_intf;
+  playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                             FIND_ANYWHERE );
+
+  msg_Warn (servant->p_intf, "Calling MediaControl::stop");
+
+  if( p_playlist != NULL )
+    {
+      playlist_Stop( p_playlist );
+      vlc_object_release( p_playlist );
+    }
+
+  return;
+}
+
+static void
+impl_VLC_MediaControl_exit(impl_POA_VLC_MediaControl * servant,
+                           CORBA_Environment * ev)
+{
+  msg_Warn (servant->p_intf, "Calling MediaControl::exit");
+
+  vlc_mutex_lock( &servant->p_intf->change_lock );
+  servant->p_intf->b_die = TRUE;
+  vlc_mutex_unlock( &servant->p_intf->change_lock );
+}
+
+static void
+impl_VLC_MediaControl_add_to_playlist(impl_POA_VLC_MediaControl * servant,
+                                      const CORBA_char * psz_file,
+                                      CORBA_Environment * ev)
+{
+  intf_thread_t *  p_intf = servant->p_intf;
+  playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                             FIND_ANYWHERE );
+
+  msg_Warn (servant->p_intf, "Calling MediaControl::add_to_playlist %s", psz_file);
+
+  if ( p_playlist == NULL )
+    {
+      msg_Err (servant->p_intf, "Error: no playlist defined");
+      /* FIXME: should return an exception */
+      return;
+    }
+
+  playlist_Add (p_playlist, psz_file, PLAYLIST_REPLACE, 0);
+  vlc_object_release( p_playlist );
+
+  return;
+}
+
+static VLC_PlaylistSeq *
+impl_VLC_MediaControl_get_playlist(impl_POA_VLC_MediaControl * servant,
+                                   CORBA_Environment * ev)
+{
+   VLC_PlaylistSeq *retval;
+   int i_index;
+   intf_thread_t *  p_intf = servant->p_intf;
+   playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+                                              FIND_ANYWHERE );
+   int i_playlist_size;
+
+   msg_Warn (servant->p_intf, "Calling MediaControl::get_playlist");
+
+   vlc_mutex_lock( &p_playlist->object_lock );
+   i_playlist_size = p_playlist->i_size;
+
+   retval = VLC_PlaylistSeq__alloc ();
+   retval->_buffer = VLC_PlaylistSeq_allocbuf (i_playlist_size);
+   retval->_length = i_playlist_size;
+
+   for (i_index = 0 ; i_index < i_playlist_size ; i_index++)
+     {
+       retval->_buffer[i_index] =
+         CORBA_string_dup (p_playlist->pp_items[i_index]->psz_name);
+     }
+   vlc_mutex_unlock( &p_playlist->object_lock );
+   vlc_object_release( p_playlist );
+
+   CORBA_sequence_set_release (retval, TRUE);
+   return retval;
+}
+
+/* (Real) end of the CORBA code generated in Mediacontrol-skelimpl.c */
+
+/*****************************************************************************
+ * Local prototypes.
+ *****************************************************************************/
+static int  Open         ( vlc_object_t * );
+static void Close        ( vlc_object_t * );
+static void Run          ( intf_thread_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    add_category_hint( N_("Corba control"), NULL, VLC_FALSE );
+    set_description( _("corba control module") );
+    set_capability( "interface", 10 );
+    set_callbacks( Open, Close );
+vlc_module_end();
+
+/*****************************************************************************
+ * intf_Open: initialize and create stuff
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+  intf_thread_t *p_intf = (intf_thread_t *)p_this;
+
+  /* Allocate instance and initialize some members */
+  p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
+  if( p_intf->p_sys == NULL )
+    {
+      msg_Err( p_intf, "out of memory" );
+      return VLC_ENOMEM;
+    }
+
+  /* Initialize the fields of the p_intf struct */
+  p_intf->pf_run = Run;
+  p_intf->p_sys->b_playing = VLC_FALSE;
+  p_intf->p_sys->p_input = NULL;
+
+  p_intf->p_sys->orb = NULL;
+  p_intf->p_sys->mc = NULL;
+  p_intf->p_sys->root_poa = NULL;
+  p_intf->p_sys->root_poa_manager = NULL;
+  p_intf->p_sys->corbaloop = NULL;
+
+  return VLC_SUCCESS;
+}
+
+
+
+/*****************************************************************************
+ * intf_Close: destroy interface
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+  intf_thread_t *p_intf = (intf_thread_t *)p_this;
+  CORBA_Environment*        ev = NULL;
+
+  ev = CORBA_exception__alloc ();
+  CORBA_ORB_shutdown (p_intf->p_sys->orb, FALSE, ev);
+  handle_exception_no_servant (p_intf, "Erreur dans Close");
+
+  if( p_intf->p_sys->p_input )
+    {
+      vlc_object_release( p_intf->p_sys->p_input );
+    }
+
+  /* Destroy structure */
+  free( p_intf->p_sys );
+}
+
+/*
+  Function called regularly to handle various tasks (mainly CORBA calls)
+ */
+static gboolean Manage (gpointer p_interface)
+{
+  intf_thread_t *p_intf = (intf_thread_t*)p_interface;
+  CORBA_boolean b_work_pending;
+  CORBA_Environment* ev;
+
+  ev = CORBA_exception__alloc ();
+
+  /* CORBA */
+  b_work_pending = CORBA_ORB_work_pending (p_intf->p_sys->orb, ev);
+  if(ev->_major != CORBA_NO_EXCEPTION)
+    {
+      msg_Err (p_intf, "Exception dans la vérif d'événements CORBA");
+      return FALSE;
+    }
+
+  vlc_mutex_lock( &p_intf->change_lock );
+
+  /* Update the input */
+  if( p_intf->p_sys->p_input == NULL )
+    {
+      p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
+                                                FIND_ANYWHERE );
+    }
+  else if( p_intf->p_sys->p_input->b_dead )
+    {
+      vlc_object_release( p_intf->p_sys->p_input );
+      p_intf->p_sys->p_input = NULL;
+    }
+
+  if( p_intf->p_sys->p_input )
+    {
+      input_thread_t  *p_input = p_intf->p_sys->p_input;
+
+      vlc_mutex_lock( &p_input->stream.stream_lock );
+
+      if ( !p_input->b_die )
+        {
+          /* New input or stream map change */
+          if( p_input->stream.b_changed )
+            {
+              /* FIXME: We should notify our client that the input changed */
+              /* E_(GtkModeManage)( p_intf ); */
+              p_intf->p_sys->b_playing = 1;
+            }
+        }
+      vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+  else if( p_intf->p_sys->b_playing && !p_intf->b_die )
+    {
+      /* FIXME: We should notify our client that the input changed */
+      /* E_(GtkModeManage)( p_intf ); */
+      p_intf->p_sys->b_playing = 0;
+    }
+
+  /* CORBA calls handling. Beware: no lock is taken (since p_pinput
+     can be null) */
+  if (b_work_pending)
+    CORBA_ORB_perform_work (p_intf->p_sys->orb, ev);
+
+  if( p_intf->b_die )
+    {
+      vlc_mutex_unlock( &p_intf->change_lock );
+      g_main_loop_quit (p_intf->p_sys->corbaloop);
+      /* Just in case */
+      return( FALSE );
+    }
+
+  vlc_mutex_unlock( &p_intf->change_lock );
+
+  return TRUE;
+}
+
+/*****************************************************************************
+ * Run: main loop
+ *****************************************************************************
+ * this part of the interface is in a separate thread so that we can call
+ * g_main_loop_run() from within it without annoying the rest of the program.
+ *****************************************************************************/
+static void Run ( intf_thread_t *p_intf )
+{
+  CORBA_Environment*        ev = NULL;
+  guint                     i_event_source;
+  CORBA_char*               psz_objref;
+  impl_POA_VLC_MediaControl *servant = NULL;
+  int i_argc = 1;
+  char* ppsz_argv[] = { "mc" };
+
+  msg_Warn (p_intf, "Entering Run");
+
+  ev = CORBA_exception__alloc ();
+
+  /* To be able to use CORBA in a MT app */
+  linc_set_threaded (TRUE);
+
+  p_intf->p_sys->orb = CORBA_ORB_init(&i_argc, ppsz_argv, "orbit-local-orb", ev);
+
+  /* Should be cleaner this way (cf
+     http://www.fifi.org/doc/gnome-dev-doc/html/C/orbitgtk.html) but it
+     functions well enough in the ugly way so that I do not bother
+     cleaning it */
+  /* p_intf->p_sys->orb = gnome_CORBA_init ("VLC", NULL, &argc, &argv, 0, NULL, ev); */
+
+  handle_exception_no_servant (p_intf, "Exception during CORBA_ORB_init");
+
+  p_intf->p_sys->root_poa = (PortableServer_POA)CORBA_ORB_resolve_initial_references(p_intf->p_sys->orb, "RootPOA", ev);
+  handle_exception ("Exception during RootPOA initialization");
+
+  p_intf->p_sys->mc = impl_VLC_MediaControl__create(p_intf->p_sys->root_poa, ev);
+  handle_exception ("Exception during MediaControl initialization");
+
+  servant = (impl_POA_VLC_MediaControl*)PortableServer_POA_reference_to_servant(p_intf->p_sys->root_poa, p_intf->p_sys->mc, ev);
+  handle_exception ("Exception during MediaControl access");
+
+  servant->p_intf = p_intf;
+
+  psz_objref = CORBA_ORB_object_to_string(p_intf->p_sys->orb, p_intf->p_sys->mc, ev);
+  handle_exception ("Exception during IOR generation");
+
+  msg_Warn (p_intf, "MediaControl IOR :");
+  msg_Warn (p_intf, psz_objref);
+
+  /* We write the IOR in a file. */
+  {
+    FILE* fp;
+    fp = fopen (VLC_IOR_FILE, "w");
+    if (fp == NULL)
+      {
+        msg_Err (servant->p_intf, "Cannot write the IOR to %s (%d).", VLC_IOR_FILE, errno);
+      }
+    else
+      {
+        fprintf (fp, "%s", psz_objref);
+        fclose (fp);
+        msg_Warn (servant->p_intf, "IOR written to %s", VLC_IOR_FILE);
+      }
+  }
+
+  msg_Warn (p_intf, "get_the_POAManager (state  %s)", p_intf->p_sys->root_poa);
+  p_intf->p_sys->root_poa_manager = PortableServer_POA__get_the_POAManager(p_intf->p_sys->root_poa, ev);
+  handle_exception ("Exception during POAManager resolution");
+
+  msg_Warn (p_intf, "Activating POAManager");
+  PortableServer_POAManager_activate(p_intf->p_sys->root_poa_manager, ev);
+  handle_exception ("Exception during POAManager activation");
+
+  msg_Info(p_intf, "corba remote control interface initialized" );
+
+  /*
+    // Tentative de gestion du nommage...
+  {
+    CosNaming_NamingContext name_service;
+    CosNaming_NameComponent name_component[3] = {{"GNOME", "subcontext"},
+                                                 {"Servers", "subcontext"},
+                                                 {"vlc", "server"} };
+    CosNaming_Name name = {3, 3, name_component, CORBA_FALSE};
+
+    name_service = CORBA_ORB_resolve_initial_references (p_intf->p_sys->orb,
+                                                         "NameService",
+                                                         ev);
+    handle_exception ("Error: could not get name service: %s\n",
+                   CORBA_exception_id(ev));
+    msg_Warn (p_intf, "Name service OK");
+
+    CosNaming_NamingContext_bind (name_service, &name, p_intf->p_sys->mc, ev);
+      handle_exception ("Error: could not register object: %s\n",
+      CORBA_exception_id(ev));
+  }
+    */
+
+  /* The time factor should be 1/1000 but it is a little too
+     slow. Make it 1/10000 */
+  i_event_source = g_timeout_add (INTF_IDLE_SLEEP / 10000,
+                                Manage,
+                                p_intf);
+  msg_Warn (p_intf, "Entering mainloop");
+
+  p_intf->p_sys->corbaloop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (p_intf->p_sys->corbaloop);
+
+  /* Cleaning */
+  g_source_remove( i_event_source );
+  unlink (VLC_IOR_FILE);
+
+  msg_Warn (p_intf, "Normal termination of VLC corba plugin");
+  return;
+}
diff --git a/modules/control/corba/launch-vlc-corba b/modules/control/corba/launch-vlc-corba
new file mode 100644 (file)
index 0000000..2647af3
--- /dev/null
@@ -0,0 +1,7 @@
+#! /bin/sh
+# Helper prog
+VLCPATH=/usr/local/src/vlc
+cd $VLCPATH
+${VLCPATH}/vlc --intf corba &
+exit 0
+
diff --git a/modules/control/corba/mediacontrol.idl b/modules/control/corba/mediacontrol.idl
new file mode 100644 (file)
index 0000000..8fdda03
--- /dev/null
@@ -0,0 +1,55 @@
+/* Cf
+   http://www.cs.rpi.edu/~musser/dsc/idl/idl-overview.html
+   pour une intro à la syntaxe */
+
+module VLC {
+   enum PositionOrigin {
+       AbsolutePosition, RelativePosition, ModuloPosition
+   };
+   
+   enum PositionKey {
+       ByteCount, SampleCount, MediaTime
+   };
+   
+   struct Position {
+       PositionOrigin origin;
+       PositionKey key;
+       long value;
+   };
+   
+   exception PositionKeyNotSupported { PositionKey key;};
+   exception InvalidPosition { PositionKey key;};
+
+  typedef sequence<string> PlaylistSeq; 
+
+   // MediaControl interface is similar to
+   // ControlledStream interface in MSS.
+   // It can be inherited by flow endpoints or
+   // FlowConnection interfaces.
+  interface MediaControl
+  {
+    
+    exception PositionKeyNotSupported { PositionKey key;};
+    
+    Position get_media_position(
+                               in PositionOrigin an_origin,
+                               in PositionKey a_key)
+      raises (PositionKeyNotSupported);
+    
+    void set_media_position(in Position a_position)
+      raises (PositionKeyNotSupported, InvalidPosition);
+     
+    void start(in Position a_position)
+      raises(InvalidPosition);
+    void pause(in Position a_position)
+      raises(InvalidPosition);
+    void resume(in Position a_position)
+      raises(InvalidPosition);
+    void stop(in Position a_position)
+      raises(InvalidPosition);
+    void exit (); // Exits the player (not in the original spec)
+    void add_to_playlist (in string a_file);
+    // Returns the list of files in playlist
+    PlaylistSeq get_playlist ();
+  };
+};
diff --git a/modules/control/corba/pyorbit-1.99.3.patch b/modules/control/corba/pyorbit-1.99.3.patch
new file mode 100644 (file)
index 0000000..7c4cefa
--- /dev/null
@@ -0,0 +1,48 @@
+--- pyorbit-1.99.3/src/pycorba-orb.c    2002-11-16 07:51:41.000000000 +0100
++++ pyorbit-1.99.3-modif/src/pycorba-orb.c      2003-01-22 14:43:30.000000000 +0100
+@@ -154,6 +154,36 @@
+     return Py_None;
+ }
++static PyObject *
++pycorba_orb_work_pending(PyCORBA_ORB *self)
++{
++    CORBA_boolean ret;
++    CORBA_Environment ev;
++    PyObject *py_ret;
++
++    CORBA_exception_init(&ev);
++    ret = CORBA_ORB_work_pending (self->orb, &ev);
++
++    if (pyorbit_check_ex(&ev))
++        return NULL;
++    py_ret = ret ? Py_True : Py_False;
++    Py_INCREF(py_ret);
++    return py_ret;
++}
++
++static PyObject *
++pycorba_orb_perform_work (PyCORBA_ORB *self)
++{
++    CORBA_Environment ev;
++
++    CORBA_exception_init(&ev);
++    CORBA_ORB_perform_work (self->orb, &ev);
++    if (pyorbit_check_ex(&ev))
++       return NULL;
++    Py_INCREF(Py_None);
++    return Py_None;
++}
++
+ static PyMethodDef pycorba_orb_methods[] = {
+     { "object_to_string", (PyCFunction)pycorba_orb_object_to_string, METH_VARARGS },
+     { "string_to_object", (PyCFunction)pycorba_orb_string_to_object, METH_VARARGS },
+@@ -161,6 +191,8 @@
+     { "resolve_initial_references", (PyCFunction)pycorba_orb_resolve_initial_references, METH_VARARGS },
+     { "run", (PyCFunction)pycorba_orb_run, METH_NOARGS },
+     { "shutdown", (PyCFunction)pycorba_orb_shutdown, METH_VARARGS },
++    { "work_pending", (PyCFunction)pycorba_orb_work_pending, METH_VARARGS },
++    { "perform_work", (PyCFunction)pycorba_orb_perform_work, METH_VARARGS },
+     { NULL, NULL, 0 }
+ };
diff --git a/modules/control/corba/simpleplayer.glade b/modules/control/corba/simpleplayer.glade
new file mode 100644 (file)
index 0000000..da6aebc
--- /dev/null
@@ -0,0 +1,402 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="win">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">DVD Annote</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <signal name="delete_event" handler="on_exit" object="win" last_modification_time="Mon, 27 Jan 2003 14:07:29 GMT"/>
+  <signal name="key_press_event" handler="on_win_key_press_event" last_modification_time="Mon, 17 Feb 2003 16:23:35 GMT"/>
+
+  <child>
+    <widget class="GtkVBox" id="vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+       <widget class="GtkMenuBar" id="menubar">
+         <property name="visible">True</property>
+
+         <child>
+           <widget class="GtkMenuItem" id="menuitem1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_File</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="menuitem1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="quit1">
+                     <property name="visible">True</property>
+                     <property name="label">gtk-quit</property>
+                     <property name="use_stock">True</property>
+                     <signal name="activate" handler="on_exit" last_modification_time="Mon, 27 Jan 2003 14:07:57 GMT"/>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="menuitem4">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Help</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="menuitem4_menu">
+
+                 <child>
+                   <widget class="GtkMenuItem" id="about1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_About</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_about1_activate" last_modification_time="Mon, 27 Jan 2003 14:07:57 GMT"/>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHButtonBox" id="hbuttonbox2">
+         <property name="visible">True</property>
+         <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkButton" id="b_rewind">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Rewind</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label" translatable="yes">Rewind</property>
+             <property name="use_underline">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_rewind_clicked" last_modification_time="Mon, 27 Jan 2003 14:19:30 GMT"/>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="b_play">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Play</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label" translatable="yes">Play</property>
+             <property name="use_underline">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_play_clicked" last_modification_time="Mon, 27 Jan 2003 14:19:50 GMT"/>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="b_pause">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Pause</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label" translatable="yes">Pause</property>
+             <property name="use_underline">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_pause_clicked" last_modification_time="Mon, 27 Jan 2003 14:19:56 GMT"/>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="b_stop">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Stop</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label" translatable="yes">Stop</property>
+             <property name="use_underline">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_stop_clicked" last_modification_time="Mon, 27 Jan 2003 14:20:03 GMT"/>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="b_forward">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Forward</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label" translatable="yes">Forward</property>
+             <property name="use_underline">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_forward_clicked" last_modification_time="Mon, 27 Jan 2003 14:20:10 GMT"/>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="b_addfile">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Add file</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label" translatable="yes">Add file...</property>
+             <property name="use_underline">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_addfile_clicked" last_modification_time="Mon, 27 Jan 2003 14:20:15 GMT"/>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="b_selectdvd">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Select DVD</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label" translatable="yes">Play DVD</property>
+             <property name="use_underline">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_selectdvd_clicked" last_modification_time="Mon, 27 Jan 2003 14:20:15 GMT"/>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="b_exit">
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Exit</property>
+             <property name="can_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="label">gtk-quit</property>
+             <property name="use_stock">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="on_b_exit_clicked" last_modification_time="Mon, 27 Jan 2003 14:20:26 GMT"/>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkFrame" id="Information">
+         <property name="visible">True</property>
+         <property name="label_xalign">0</property>
+         <property name="label_yalign">0.5</property>
+         <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+         <child>
+           <widget class="GtkTable" id="table1">
+             <property name="visible">True</property>
+             <property name="n_rows">1</property>
+             <property name="n_columns">2</property>
+             <property name="homogeneous">True</property>
+             <property name="row_spacing">0</property>
+             <property name="column_spacing">10</property>
+
+             <child>
+               <widget class="GtkLabel" id="label5">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Position</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">10</property>
+                 <property name="ypad">2</property>
+               </widget>
+               <packing>
+                 <property name="left_attach">0</property>
+                 <property name="right_attach">1</property>
+                 <property name="top_attach">0</property>
+                 <property name="bottom_attach">1</property>
+                 <property name="x_options">fill</property>
+                 <property name="y_options"></property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="position_label">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">N/C</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="left_attach">1</property>
+                 <property name="right_attach">2</property>
+                 <property name="top_attach">0</property>
+                 <property name="bottom_attach">1</property>
+                 <property name="x_options">fill</property>
+                 <property name="y_options"></property>
+               </packing>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkLabel" id="label1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">Information</property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">False</property>
+             <property name="justify">GTK_JUSTIFY_LEFT</property>
+             <property name="wrap">False</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="type">label_item</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkScrolledWindow" id="scrolledwindow1">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+         <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+         <property name="shadow_type">GTK_SHADOW_NONE</property>
+         <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+         <child>
+           <widget class="GtkTextView" id="logmessages">
+             <property name="height_request">100</property>
+             <property name="visible">True</property>
+             <property name="can_focus">True</property>
+             <property name="editable">False</property>
+             <property name="justification">GTK_JUSTIFY_LEFT</property>
+             <property name="wrap_mode">GTK_WRAP_CHAR</property>
+             <property name="cursor_visible">False</property>
+             <property name="pixels_above_lines">0</property>
+             <property name="pixels_below_lines">0</property>
+             <property name="pixels_inside_wrap">0</property>
+             <property name="left_margin">0</property>
+             <property name="right_margin">0</property>
+             <property name="indent">0</property>
+             <property name="text" translatable="yes"></property>
+             <signal name="insert_at_cursor" handler="on_logmessages_insert_at_cursor" last_modification_time="Mon, 27 Jan 2003 14:09:43 GMT"/>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+<widget class="GtkWindow" id="about">
+  <property name="title" translatable="yes">About</property>
+  <property name="type">GTK_WINDOW_POPUP</property>
+  <property name="window_position">GTK_WIN_POS_CENTER</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+
+  <child>
+    <widget class="GtkFrame" id="frame2">
+      <property name="visible">True</property>
+      <property name="label_xalign">0</property>
+      <property name="label_yalign">0.5</property>
+      <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+      <child>
+       <widget class="GtkVBox" id="vbox2">
+         <property name="visible">True</property>
+         <property name="homogeneous">False</property>
+         <property name="spacing">0</property>
+
+         <child>
+           <widget class="GtkLabel" id="label4">
+             <property name="width_request">280</property>
+             <property name="height_request">64</property>
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">DVD Annotation
+
+En cours de developpement...</property>
+             <property name="use_underline">False</property>
+             <property name="use_markup">True</property>
+             <property name="justify">GTK_JUSTIFY_CENTER</property>
+             <property name="wrap">True</property>
+             <property name="selectable">False</property>
+             <property name="xalign">0.5</property>
+             <property name="yalign">0.5</property>
+             <property name="xpad">0</property>
+             <property name="ypad">0</property>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkButton" id="button1">
+             <property name="border_width">1</property>
+             <property name="width_request">54</property>
+             <property name="height_request">34</property>
+             <property name="visible">True</property>
+             <property name="tooltip" translatable="yes">Close about box</property>
+             <property name="can_default">True</property>
+             <property name="has_default">True</property>
+             <property name="can_focus">True</property>
+             <property name="has_focus">True</property>
+             <property name="label">gtk-ok</property>
+             <property name="use_stock">True</property>
+             <property name="relief">GTK_RELIEF_NORMAL</property>
+             <signal name="clicked" handler="about_hide" object="about" last_modification_time="Wed, 29 Jan 2003 12:52:15 GMT"/>
+             <accelerator key="Escape" modifiers="0" signal="clicked"/>
+             <accelerator key="Return" modifiers="0" signal="clicked"/>
+           </widget>
+           <packing>
+             <property name="padding">0</property>
+             <property name="expand">False</property>
+             <property name="fill">False</property>
+           </packing>
+         </child>
+       </widget>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/modules/control/corba/simpleplayer.py b/modules/control/corba/simpleplayer.py
new file mode 100644 (file)
index 0000000..d437119
--- /dev/null
@@ -0,0 +1,298 @@
+#!/usr/bin/env python
+
+import sys, time
+
+# For gtk/glade
+import pygtk
+pygtk.require ('2.0')
+import gtk
+import gtk.glade
+
+# For CORBA
+import ORBit, CORBA
+# FIXME: How do we make this portable to windows ?
+ORBit.load_typelib ("./MediaControl.so")
+import VLC
+
+class Connect:
+    """Abstract class defining helper functions to interconnect
+    glade XML files and methods of a python class."""    
+    def create_dictionary (self):
+        """Create a (name, function) dictionnary for the current class"""
+        dict = {}
+        self.create_dictionary_for_class (self.__class__, dict)
+        return dict
+    
+    def create_dictionary_for_class (self, a_class, dict):
+        """Create a (name, function) dictionnary for the specified class"""
+        bases = a_class.__bases__
+        for iteration in bases:
+            self.create_dictionary_for_class (iteration, dict)
+        for iteration in dir(a_class):
+            dict[iteration] = getattr(self, iteration)
+
+    def connect (self):
+        """Connects the class methods with the UI"""
+        self.gui.signal_autoconnect(self.create_dictionary ())
+
+    def gtk_widget_hide (self, widget):
+        widget.hide ()
+        return gtk.TRUE
+        
+    def on_exit(self, source=None, event=None):
+        """Generic exit callback"""
+        gtk.main_quit()
+
+class DVDControl (Connect):
+    def __init__ (self, gladefile):
+        """Initializes the GUI and other attributes"""
+        # Glade init.
+        self.gui = gtk.glade.XML(gladefile)
+        self.connect ()
+        # Frequently used GUI widgets
+        self.gui.logmessages = self.gui.get_widget("logmessages")
+        self.gui.position_label = self.gui.get_widget("position_label")
+        self.gui.fs = gtk.FileSelection ("Select a file")
+        self.gui.fs.ok_button.connect_after ("clicked", lambda win: self.gui.fs.hide ())
+        self.gui.fs.cancel_button.connect ("clicked", lambda win: self.gui.fs.destroy ())
+
+        # CORBA init.
+        self.mc = None
+        self.currentpos = None
+        self.status = None
+        # FIXME: portability
+        self.iorfile = "/tmp/vlc-ior.ref"
+        
+        # Various
+        # Default FF/RW time : 5 seconds
+        self.default_time_increment = 5
+
+    def update_title (self, title):
+        # Update the title of the main window
+        self.gui.get_widget ("win").set_title (title)
+        
+    def launch_player (self):
+        """Launch the VLC corba plugin"""
+        #print "Launching vlc server..."
+        # FIXME: spawn is portable, but how can we make sure that
+        # launch-vlc-corba launches the application in the background ?
+        # FIXME: portability
+        import distutils.spawn
+        distutils.spawn.spawn (["launch-vlc-corba"], True, True)
+        # Wait a little for the server to initialize. We could instead test
+        # on the existence and validity of self.iorfile
+        time.sleep (2)
+        return
+
+    def main (self):
+        """Mainloop : CORBA initalization and Gtk mainloop setup"""
+        self.orb = CORBA.ORB_init(sys.argv)
+
+        errormessage = """Unable to get a MediaControl object
+Please try to run the following command:
+vlc --intf corba"""
+        
+        try:
+            ior = open(self.iorfile).readline()
+        except:
+            # The iorfile does not existe : the player is maybe not active
+            self.launch_player ()
+            try:
+                ior = open(self.iorfile).readline()
+            except:
+                print errormessage
+                sys.exit(1)
+
+        self.mc = self.orb.string_to_object(ior)
+
+        if self.mc._non_existent ():
+            # The remote object is not available. Let's run the
+            # VLC server
+            self.launch_player ()
+            try:
+                ior = open(self.iorfile).readline()
+            except:
+                print errormessage
+                sys.exit(1)
+            self.mc = self.orb.string_to_object(ior)
+            if self.mc._non_existent ():
+                print errormessage
+                sys.exit(1)
+
+        self.currentpos = VLC.Position ()
+        self.currentpos.value = 0
+        self.currentpos.key = VLC.MediaTime
+        self.currentpos.origin = VLC.RelativePosition
+            
+        gtk.timeout_add (20, self.update_display, self.orb)
+        gtk.main ()
+
+    def log (self, msg):
+        """Adds a new log message to the logmessage window"""
+        buf = self.gui.logmessages.get_buffer ()
+        mes = str(msg) + "\n"
+        buf.insert_at_cursor (mes, len(mes))
+
+        endmark = buf.create_mark ("end",
+                                   buf.get_end_iter (),
+                                   gtk.TRUE)
+        self.gui.logmessages.scroll_mark_onscreen (endmark)
+        return
+        
+    def on_exit (self, source=None, event=None):
+        """General exit callback"""
+        self.status = "Stop"
+        # Terminate the VLC server
+        try:
+            self.mc.exit()
+        except:
+            pass
+        gtk.main_quit ()
+
+    def file_selector (self, callback=None, label="Select a file",
+                       default=""):
+        """Display the file selector"""
+        self.gui.fs.set_property ("title", label)
+        self.gui.fs.set_property ("filename", default)
+        self.gui.fs.set_property ("select-multiple", False)
+        self.gui.fs.set_property ("show-fileops", False)
+
+        if callback:
+            # Disconnecting the old callback
+            try:
+                self.gui.fs.ok_button.disconnect (self.gui.fs.connect_id)
+            except:
+                pass
+            # Connecting the new one
+            self.gui.fs.connect_id = self.gui.fs.ok_button.connect ("clicked", callback, self.gui.fs)
+        self.gui.fs.show ()
+       return gtk.TRUE
+
+    def file_selected_cb (self, button, fs):
+        """Open and play the selected movie file"""
+        file = self.gui.fs.get_property ("filename")
+        self.mc.add_to_playlist (file)
+        self.status = "Play"
+        return gtk.TRUE
+
+    def move_position (self, value):
+        """Helper function : fast forward or rewind by value seconds"""
+        print "Moving by %d seconds" % value
+        pos = VLC.Position ()
+        pos.value = value
+        pos.key = VLC.MediaTime
+        pos.origin = VLC.RelativePosition
+        self.mc.set_media_position (pos)
+        return
+
+    def update_display (self, orb):
+        """Update the interface"""
+        if self.status == "Play":
+            pos = self.mc.get_media_position (VLC.AbsolutePosition,
+                                              VLC.ByteCount)
+            self.gui.position_label.set_text (str(pos.value))
+        elif self.status == "Stop":
+            self.gui.position_label.set_text ("N/C")
+        return gtk.TRUE
+
+    # Callbacks function. Skeletons can be generated by glade2py
+    def on_win_key_press_event (self, win=None, event=None):
+        # Navigation keys
+        if event.keyval == gtk.keysyms.Tab:
+            self.on_b_pause_clicked (win, event)
+            return gtk.TRUE
+        elif event.keyval == gtk.keysyms.Right:
+            self.on_b_forward_clicked (win, event)
+            return gtk.TRUE
+        elif event.keyval == gtk.keysyms.Left:
+            self.on_b_rewind_clicked (win, event)
+            return gtk.TRUE
+        elif event.keyval == gtk.keysyms.Home:
+            pos = VLC.Position ()
+            pos.value = 0
+            pos.key = VLC.MediaTime
+            pos.origin = VLC.AbsolutePosition
+            self.mc.set_media_position (pos)
+            return gtk.TRUE
+        elif event.keyval == gtk.keysyms.End:
+            pos = VLC.Position ()
+            pos.value = -self.default_time_increment
+            pos.key = VLC.MediaTime
+            pos.origin = VLC.ModuloPosition
+            self.mc.set_media_position (pos)
+            return gtk.TRUE
+        elif event.keyval == gtk.keysyms.Page_Down:
+            # FIXME: Next chapter
+            return gtk.TRUE
+        elif event.keyval == gtk.keysyms.Page_Up:
+            # FIXME: Previous chapter
+            return gtk.TRUE
+        return gtk.TRUE
+
+    def on_quit1_activate (self, button=None, data=None):
+        """Gtk callback to quit"""
+        self.on_exit (button, data)
+        return gtk.TRUE
+    
+    def on_about1_activate (self, button=None, data=None):
+        self.gui.get_widget("about").show ()
+       return gtk.TRUE
+
+    def about_hide (self, button=None, data=None):
+        self.gui.get_widget("about").hide ()
+       return gtk.TRUE
+        
+    def on_b_rewind_clicked (self, button=None, data=None):
+        if self.status == "Play":
+            self.move_position (-self.default_time_increment)
+       return gtk.TRUE
+
+    def on_b_play_clicked (self, button=None, data=None):
+        if self.status != "Play":
+            self.mc.start (self.currentpos)
+            self.status = "Play"
+        return gtk.TRUE
+
+    def on_b_pause_clicked (self, button=None, data=None):
+        if self.status == "Play":
+            self.mc.pause (self.currentpos)
+            self.status = "Pause"
+        elif self.status == "Pause":
+            self.mc.pause (self.currentpos)
+            self.status = "Play"
+       return gtk.TRUE
+
+    def on_b_stop_clicked (self, button=None, data=None):
+        self.mc.stop (self.currentpos)
+        self.status = "Stop"
+       return gtk.TRUE
+
+    def on_b_forward_clicked (self, button=None, data=None):
+        if self.status == "Play":
+            self.move_position (self.default_time_increment)
+       return gtk.TRUE
+
+    def on_b_addfile_clicked (self, button=None, data=None):
+        self.file_selector (callback=self.file_selected_cb,
+                            label="Play a movie file")
+       return gtk.TRUE
+
+    def on_b_selectdvd_clicked (self, button=None, data=None):
+        """Play a DVD"""
+        self.mc.add_to_playlist ("dvd:///dev/dvd at 1,1")
+        self.mc.start (self.currentpos)
+        self.status = "Play"
+        return gtk.TRUE
+    
+    def on_b_exit_clicked (self, button=None, data=None):
+        self.on_exit (button, data)
+       return gtk.TRUE
+
+    def on_logmessages_insert_at_cursor (self, button=None, data=None):
+       print "on_logmessages_insert_at_cursor activated (%s, %s, %s)" % (self, button, data)
+        # FIXME: faire défiler la scrollmark (cf gtkshell)
+       return gtk.TRUE
+
+if __name__ == '__main__':
+    v = DVDControl ("simpleplayer.glade")
+    v.main ()
index fe8ae742717d0415f814bf7a8ed131b4b7d386be..c6149d1357593be17db38d7c181aca06e736850d 100644 (file)
@@ -2,7 +2,7 @@
  * playlist.c : Playlist management functions
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: playlist.c,v 1.40 2003/06/27 13:38:54 sam Exp $
+ * $Id: playlist.c,v 1.41 2003/07/07 16:59:00 sam Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
@@ -412,6 +412,7 @@ void playlist_Command( playlist_t * p_playlist, int i_command, int i_arg )
         p_playlist->i_status = PLAYLIST_RUNNING;
         if( p_playlist->p_input )
         {
+            PlayItem( p_playlist );
             input_SetStatus( p_playlist->p_input, INPUT_STATUS_PLAY );
         }
         break;