Initial support of one instance mode on systems running D-Bus
authorRafaël Carré <funman@videolan.org>
Sun, 19 Nov 2006 22:46:25 +0000 (22:46 +0000)
committerRafaël Carré <funman@videolan.org>
Sun, 19 Nov 2006 22:46:25 +0000 (22:46 +0000)
include/vlc_common.h
modules/control/dbus.c
modules/control/dbus.h
src/libvlc-common.c
src/libvlc.h

index 85e6500..58c64fe 100644 (file)
@@ -1176,3 +1176,10 @@ VLC_EXPORT( const char *, VLC_Changeset, ( void ) );
 #   define DIR_SEP_CHAR '/'
 #   define DIR_SEP "/"
 #endif
+
+#ifdef HAVE_DBUS_3
+/* registered name on the session bus */
+#define VLC_DBUS_SERVICE        "org.videolan.vlc"
+#define VLC_DBUS_INTERFACE      "org.videolan.vlc"
+#define VLC_DBUS_OBJECT_PATH    "/org/videolan/vlc"
+#endif
index aef3024..0ab1ec7 100644 (file)
@@ -251,7 +251,7 @@ DBUS_METHOD( AddMRL )
     if( p_item )
     {
         playlist_AddInput( p_playlist, p_item,
-            ( b_play == TRUE ) ? PLAYLIST_GO|PLAYLIST_APPEND : PLAYLIST_APPEND,
+            PLAYLIST_APPEND | ( ( b_play == TRUE ) ? PLAYLIST_GO : 0 ) ,
             PLAYLIST_END, VLC_TRUE );
     }
     pl_Release( p_playlist );
@@ -331,17 +331,8 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-    /* we request the service org.videolan.vlc */    
-    dbus_bus_request_name( p_conn, VLC_DBUS_SERVICE,
-            DBUS_NAME_FLAG_REPLACE_EXISTING , &error );
-    if (dbus_error_is_set( &error ) )
-    { 
-        msg_Err( p_this, "Error requesting %s service: %s\n", VLC_DBUS_SERVICE,
-                error.message );
-        dbus_error_free( &error );
-        free( p_sys );
-        return VLC_EGENERIC;
-    }
+    /* we unregister the object /, registered by libvlc */
+    dbus_connection_unregister_object_path( p_conn, "/" );
 
     /* we register the object /org/videolan/vlc */
     dbus_connection_register_object_path( p_conn, VLC_DBUS_OBJECT_PATH,
index 4dd8b8f..ecc4eec 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-/* DBUS IDENTIFIERS */
-
-#define VLC_DBUS_SERVICE        "org.videolan.vlc"
-#define VLC_DBUS_INTERFACE      "org.videolan.vlc"
-#define VLC_DBUS_OBJECT_PATH    "/org/videolan/vlc"
-
 /* MACROS */
 
 #define DBUS_METHOD( method_function ) \
index 3a8f3d0..83e301c 100644 (file)
 #   include <locale.h>
 #endif
 
+#ifdef HAVE_DBUS_3
+#   include <dbus/dbus.h>
+#endif
+
 #ifdef HAVE_HAL
 #   include <hal/libhal.h>
 #endif
@@ -215,6 +219,41 @@ libvlc_int_t * libvlc_InternalCreate( void )
     return p_libvlc;
 }
 
+/*
+ * D-Bus callbacks needed in libvlc_InternalInit()
+ */
+#ifdef HAVE_DBUS_3
+/* Handling of messages received on / object */
+static DBusHandlerResult handle_root
+    ( DBusConnection *p_conn, DBusMessage *p_from, void *p_data ) 
+{
+    DBusMessage* p_msg = dbus_message_new_method_return( p_from );
+    if( !p_msg ) return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    DBusMessageIter args;
+    dbus_message_iter_init_append( p_msg, &args );
+    dbus_uint32_t i_serial = 0;
+
+    char *p_root = malloc( strlen( "<node name='/'></node>" ) );
+    if (!p_root ) return DBUS_HANDLER_RESULT_NEED_MEMORY;
+    sprintf( p_root, "<node name='/'></node>" );
+
+    if( !dbus_message_iter_append_basic( &args, DBUS_TYPE_STRING, &p_root ) )
+            return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+    if( !dbus_connection_send( p_conn, p_msg, &i_serial ) )
+        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+    dbus_connection_flush( p_conn );
+    dbus_message_unref( p_msg );
+    return DBUS_HANDLER_RESULT_HANDLED;
+}
+/* vtable passed to dbus_connection_register_object_path() */
+static DBusObjectPathVTable vlc_dbus_root_vtable = {
+    NULL, handle_root, NULL, NULL, NULL, NULL
+};
+
+#endif
+
 /**
  * Initialize a libvlc instance
  * This function initializes a previously allocated libvlc instance:
@@ -569,6 +608,140 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc, char *ppsz_argv[] )
      */
     system_Configure( p_libvlc, &i_argc, ppsz_argv );
 
+#ifdef HAVE_DBUS_3
+    /* Initialise D-Bus interface, check for other instances */
+    DBusConnection  *p_conn;
+    DBusError       dbus_error;
+    int             i_dbus_service;
+
+    dbus_threads_init_default();
+    dbus_error_init( &dbus_error );
+
+    /* connect to the session bus */
+    p_conn = dbus_bus_get( DBUS_BUS_SESSION, &dbus_error );
+    if( !p_conn )
+    {
+        msg_Err( p_libvlc, "Failed to connect to the D-Bus session daemon: %s",
+                dbus_error.message );
+        dbus_error_free( &dbus_error );
+    }
+    else
+    {
+        /* we request the service org.videolan.vlc */
+        i_dbus_service = dbus_bus_request_name( p_conn, VLC_DBUS_SERVICE, 0, 
+                &dbus_error );
+        if( dbus_error_is_set( &dbus_error ) )
+        { 
+            msg_Err( p_libvlc, "Error requesting %s service: %s\n",
+                    VLC_DBUS_SERVICE, dbus_error.message );
+            dbus_error_free( &dbus_error );
+        }
+        else
+        {
+            if( i_dbus_service != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER )
+                /* TODO: register a '/' object */
+            { /*23:08 < mjj29> it should reply immediately with <node name='/'></node>*/
+
+                if( config_GetInt( p_libvlc, "one-instance" ) )
+                {
+                    msg_Warn( p_libvlc,
+                            "Another vlc instance exists: will now exit");
+
+                    int i_input;
+                    DBusMessage* p_dbus_msg;
+                    DBusMessageIter dbus_args;
+                    DBusPendingCall* p_dbus_pending;
+                    dbus_bool_t b_play;
+
+                    for( i_input = optind;i_input < i_argc;i_input++ )
+                    {
+                        msg_Dbg( p_libvlc,
+                                "Give %s to other vlc\n",ppsz_argv[i_input] );
+
+                        p_dbus_msg = dbus_message_new_method_call(
+                                VLC_DBUS_SERVICE, VLC_DBUS_OBJECT_PATH,
+                                VLC_DBUS_INTERFACE, "AddMRL" );
+
+                        if ( NULL == p_dbus_msg )
+                        {
+                            msg_Err( p_libvlc, "D-Bus problem" );
+                            system_End( p_libvlc );
+                            exit( 0 );
+                        }
+
+                        /* append MRLs */
+                        dbus_message_iter_init_append( p_dbus_msg, &dbus_args );
+                        if ( !dbus_message_iter_append_basic( &dbus_args, 
+                                    DBUS_TYPE_STRING, &ppsz_argv[i_input] ) )
+                        {
+                            msg_Err( p_libvlc, "Out of memory" );
+                            dbus_message_unref( p_dbus_msg );
+                            system_End( p_libvlc );
+                            exit( 0 );
+                        }
+                        b_play = TRUE;
+                        if( config_GetInt( p_libvlc, "playlist-enqueue" ) )
+                            b_play = FALSE;
+                        if ( !dbus_message_iter_append_basic( &dbus_args,
+                                    DBUS_TYPE_BOOLEAN, &b_play ) )
+                        {
+                            msg_Err( p_libvlc, "Out of memory" );
+                            dbus_message_unref( p_dbus_msg );
+                            system_End( p_libvlc );
+                            exit( 0 );
+                        }
+
+                        /* send message and get a handle for a reply */
+                        if ( !dbus_connection_send_with_reply ( p_conn,
+                                    p_dbus_msg, &p_dbus_pending, -1 ) )
+                        {
+                            msg_Err( p_libvlc, "D-Bus problem" );
+                            dbus_message_unref( p_dbus_msg );
+                            system_End( p_libvlc );
+                            exit( 0 );
+                        }
+
+                        if ( NULL == p_dbus_pending )
+                        {
+                            msg_Err( p_libvlc, "D-Bus problem" );
+                            dbus_message_unref( p_dbus_msg );
+                            system_End( p_libvlc );
+                            exit( 0 );
+                        }
+                        dbus_connection_flush( p_conn );
+                        dbus_message_unref( p_dbus_msg );
+                        /* block until we receive a reply */
+                        dbus_pending_call_block( p_dbus_pending );
+                        dbus_pending_call_unref( p_dbus_pending );
+                    }
+
+                    /* bye bye */
+                    system_End( p_libvlc );
+                    exit( 0 );
+                }
+                else
+                {
+                    msg_Warn( p_libvlc, 
+                            "Name %s is already owned on the session bus",
+                            VLC_DBUS_SERVICE );
+                }
+            }
+            else
+            {
+                /* register "/" object */
+                if( !dbus_connection_register_object_path( p_conn, "/", 
+                        &vlc_dbus_root_vtable, NULL ) )
+                {
+                    msg_Err( p_libvlc, "Out of memory" );
+                }
+                msg_Dbg( p_libvlc, 
+                        "We are the primary owner of %s on the session bus",
+                        VLC_DBUS_SERVICE );
+            }
+        }
+    }
+#endif
+
     /*
      * Message queue options
      */
index e76a7f0..07ea2d7 100644 (file)
@@ -875,14 +875,24 @@ static const char *ppsz_clock_descriptions[] =
 #define SYSLOG_LONGTEXT N_( \
     "Log all VLC messages to syslog (UNIX systems)." )
 
-#define ONEINSTANCE_TEXT N_("Allow only one running instance")
-#define ONEINSTANCE_LONGTEXT N_( \
+#define ONEINSTANCE_WIN_TEXT N_("Allow only one running instance")
+#define ONEINSTANCE_WIN_LONGTEXT N_( \
     "Allowing only one running instance of VLC can sometimes be useful, " \
     "for example if you associated VLC with some media types and you " \
     "don't want a new instance of VLC to be opened each time you " \
     "double-click on a file in the explorer. This option will allow you " \
     "to play the file with the already running instance or enqueue it.")
 
+#define ONEINSTANCE_DBUS_TEXT ONEINSTANCE_WIN_TEXT
+#define ONEINSTANCE_DBUS_LONGTEXT N_( \
+    "Allowing only one running instance of VLC can sometimes be useful, " \
+    "for example if you associated VLC with some media types and you " \
+    "don't want a new instance of VLC to be opened each time you " \
+    "open a file in your file manager. This option will allow you " \
+    "to play the file with the already running instance or enqueue it." \
+    "This option require the D-Bus session daemon to be active " \
+    "and the running instance of VLC to use D-Bus control interface.")
+
 #define STARTEDFROMFILE_TEXT N_("VLC is started from file association")
 #define STARTEDFROMFILE_LONGTEXT N_( \
     "Tell VLC that it is being launched due to a file association in the OS" )
@@ -1612,9 +1622,16 @@ vlc_module_begin();
         change_need_restart();
 #endif
 
+#if defined(HAVE_DBUS_3)
+    add_bool( "one-instance", 0, NULL, ONEINSTANCE_DBUS_TEXT,
+              ONEINSTANCE_DBUS_LONGTEXT, VLC_TRUE );
+    add_bool( "playlist-enqueue", 0, NULL, PLAYLISTENQUEUE_TEXT,
+              PLAYLISTENQUEUE_LONGTEXT, VLC_TRUE );
+#endif
+
 #if defined(WIN32)
-    add_bool( "one-instance", 0, NULL, ONEINSTANCE_TEXT,
-              ONEINSTANCE_LONGTEXT, VLC_TRUE );
+    add_bool( "one-instance", 0, NULL, ONEINSTANCE_WIN_TEXT,
+              ONEINSTANCE_WIN_LONGTEXT, VLC_TRUE );
     add_bool( "started-from-file", 0, NULL, STARTEDFROMFILE_TEXT,
               STARTEDFROMFILE_LONGTEXT, VLC_TRUE );
     add_bool( "one-instance-when-started-from-file", 1, NULL,