1 /*****************************************************************************
2 * dbus_root.c : dbus control module (mpris v1.0) - root object
3 *****************************************************************************
4 * Copyright © 2006-2008 Rafaël Carré
5 * Copyright © 2007-2011 Mirsal Ennaime
6 * Copyright © 2009-2011 The VideoLAN team
7 * Copyright © 2013 Alex Merry
10 * Authors: Mirsal Ennaime <mirsal at mirsal fr>
11 * Rafaël Carré <funman at videolanorg>
12 * Alex Merry <dev at randomguy3 me uk>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_interface.h>
35 #include <vlc_input.h>
37 #include <vlc_plugin.h>
38 #include <vlc_playlist.h>
43 #include "dbus_root.h"
44 #include "dbus_common.h"
46 static const char const ppsz_supported_uri_schemes[][9] = {
47 "file", "http", "https", "rtsp", "realrtsp", "pnm", "ftp", "mtp", "smb",
48 "mms", "mmsu", "mmst", "mmsh", "unsv", "itpc", "icyx", "rtmp", "rtp",
49 "dccp", "dvd", "vcd", "vcdx"
52 static const char const ppsz_supported_mime_types[][26] = {
53 "audio/mpeg", "audio/x-mpeg",
54 "video/mpeg", "video/x-mpeg",
55 "video/mpeg-system", "video/x-mpeg-system",
60 "application/ogg", "application/x-ogg",
61 "video/x-ms-asf", "video/x-ms-asf-plugin",
62 "application/x-mplayer2",
64 "video/x-google-vlc-plugin",
65 "audio/wav", "audio/x-wav",
71 "video/flv", "video/x-flv",
74 "application/xspf+xml"
78 MarshalIdentity( intf_thread_t *p_intf, DBusMessageIter *container )
81 const char *psz_id = _("VLC media player");
83 if (!dbus_message_iter_append_basic( container, DBUS_TYPE_STRING, &psz_id ))
90 MarshalCanSetFullscreen( intf_thread_t *p_intf, DBusMessageIter *container )
92 input_thread_t *p_input = NULL;
93 dbus_bool_t b_ret = FALSE;
95 if (p_intf->p_sys->p_input)
97 p_input = (input_thread_t*) vlc_object_hold( p_intf->p_sys->p_input );
98 vout_thread_t* p_vout = input_GetVout( p_input );
99 vlc_object_release( p_input );
104 vlc_object_release( p_vout );
108 if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
115 MarshalFullscreen( intf_thread_t *p_intf, DBusMessageIter *container )
117 dbus_bool_t b_fullscreen;
119 if ( p_intf->p_sys->p_playlist )
120 b_fullscreen = var_GetBool( p_intf->p_sys->p_playlist , "fullscreen" );
122 b_fullscreen = FALSE;
124 if (!dbus_message_iter_append_basic( container,
125 DBUS_TYPE_BOOLEAN, &b_fullscreen ))
131 DBUS_METHOD( FullscreenSet )
134 dbus_bool_t b_fullscreen;
135 input_thread_t *p_input = NULL;
137 if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &b_fullscreen ) )
138 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
140 if (INTF->p_sys->p_input)
142 p_input = (input_thread_t*) vlc_object_hold( INTF->p_sys->p_input );
143 vout_thread_t* p_vout = input_GetVout( p_input );
144 vlc_object_release( p_input );
147 var_SetBool( p_vout, "fullscreen", ( b_fullscreen == TRUE ) );
149 var_SetBool( PL , "fullscreen", ( b_fullscreen == TRUE ) );
156 MarshalCanQuit( intf_thread_t *p_intf, DBusMessageIter *container )
158 VLC_UNUSED( p_intf );
159 const dbus_bool_t b_ret = TRUE;
161 if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
168 MarshalCanRaise( intf_thread_t *p_intf, DBusMessageIter *container )
170 VLC_UNUSED( p_intf );
171 const dbus_bool_t b_ret = FALSE;
173 if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
180 MarshalHasTrackList( intf_thread_t *p_intf, DBusMessageIter *container )
182 VLC_UNUSED( p_intf );
183 const dbus_bool_t b_ret = FALSE;
185 if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
192 MarshalDesktopEntry( intf_thread_t *p_intf, DBusMessageIter *container )
194 VLC_UNUSED( p_intf );
195 const char* psz_ret = PACKAGE;
197 if (!dbus_message_iter_append_basic( container, DBUS_TYPE_STRING, &psz_ret ))
204 MarshalSupportedMimeTypes( intf_thread_t *p_intf, DBusMessageIter *container )
206 VLC_UNUSED( p_intf );
209 size_t i_len = sizeof( ppsz_supported_mime_types ) /
210 sizeof( *ppsz_supported_mime_types );
212 if( !dbus_message_iter_open_container( container,
213 DBUS_TYPE_ARRAY, "s",
217 for( size_t i = 0; i < i_len; ++i )
219 const char* const psz_mime_type = ppsz_supported_mime_types[i];
221 if( !dbus_message_iter_append_basic( &ret, DBUS_TYPE_STRING,
226 if( !dbus_message_iter_close_container( container, &ret ) )
233 MarshalSupportedUriSchemes( intf_thread_t *p_intf, DBusMessageIter *container )
235 VLC_UNUSED( p_intf );
238 size_t i_len = sizeof( ppsz_supported_uri_schemes ) /
239 sizeof( *ppsz_supported_uri_schemes );
241 if( !dbus_message_iter_open_container( container,
242 DBUS_TYPE_ARRAY, "s",
246 for( size_t i = 0; i < i_len; ++i )
248 const char* const psz_scheme = ppsz_supported_uri_schemes[i];
250 if( !dbus_message_iter_append_basic( &ret, DBUS_TYPE_STRING,
255 if( !dbus_message_iter_close_container( container, &ret ) )
264 libvlc_Quit(INTF->p_libvlc);
269 {/* shows vlc's main window */
271 var_ToggleBool( INTF->p_libvlc, "intf-show" );
275 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
276 #define PROPERTY_GET_FUNC( prop, signature ) \
277 else if( !strcmp( psz_property_name, #prop ) ) { \
278 if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, signature, &v ) ) \
279 return DBUS_HANDLER_RESULT_NEED_MEMORY; \
280 if( VLC_SUCCESS != Marshal##prop( p_this, &v ) ) { \
281 dbus_message_iter_abandon_container( &args, &v ); \
282 return DBUS_HANDLER_RESULT_NEED_MEMORY; \
284 if( !dbus_message_iter_close_container( &args, &v ) ) \
285 return DBUS_HANDLER_RESULT_NEED_MEMORY; \
287 #define PROPERTY_SET_FUNC( prop ) \
288 else if( !strcmp( psz_property_name, #prop ) ) { \
289 return prop##Set( p_conn, p_from, p_this ); \
291 #define PROPERTY_MAPPING_END else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
293 DBUS_METHOD( GetProperty )
297 char *psz_interface_name = NULL;
298 char *psz_property_name = NULL;
300 dbus_error_init( &error );
301 dbus_message_get_args( p_from, &error,
302 DBUS_TYPE_STRING, &psz_interface_name,
303 DBUS_TYPE_STRING, &psz_property_name,
306 if( dbus_error_is_set( &error ) )
308 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
310 dbus_error_free( &error );
311 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
314 msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
317 if( strcmp( psz_interface_name, DBUS_MPRIS_ROOT_INTERFACE ) ) {
318 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
325 PROPERTY_MAPPING_BEGIN
326 PROPERTY_GET_FUNC( Identity, "s" )
327 PROPERTY_GET_FUNC( CanSetFullscreen, "b" )
328 PROPERTY_GET_FUNC( Fullscreen, "b" )
329 PROPERTY_GET_FUNC( CanQuit, "b" )
330 PROPERTY_GET_FUNC( CanRaise, "b" )
331 PROPERTY_GET_FUNC( HasTrackList, "b" )
332 PROPERTY_GET_FUNC( DesktopEntry, "s" )
333 PROPERTY_GET_FUNC( SupportedMimeTypes, "as" )
334 PROPERTY_GET_FUNC( SupportedUriSchemes, "as" )
340 DBUS_METHOD( SetProperty )
344 char *psz_interface_name = NULL;
345 char *psz_property_name = NULL;
347 dbus_error_init( &error );
348 dbus_message_get_args( p_from, &error,
349 DBUS_TYPE_STRING, &psz_interface_name,
350 DBUS_TYPE_STRING, &psz_property_name,
353 if( dbus_error_is_set( &error ) )
355 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
357 dbus_error_free( &error );
358 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
361 PROPERTY_MAPPING_BEGIN
362 PROPERTY_SET_FUNC( Fullscreen )
366 #undef PROPERTY_MAPPING_BEGIN
367 #undef PROPERTY_GET_FUNC
368 #undef PROPERTY_SET_FUNC
369 #undef PROPERTY_MAPPING_END
371 #define ADD_PROPERTY( prop, signature ) \
372 if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_this, \
373 &dict, #prop, signature, Marshal##prop ) ) { \
374 dbus_message_iter_abandon_container( &args, &dict ); \
378 DBUS_METHOD( GetAllProperties )
384 DBusMessageIter dict;
386 char *const psz_interface_name = NULL;
388 dbus_error_init( &error );
389 dbus_message_get_args( p_from, &error,
390 DBUS_TYPE_STRING, &psz_interface_name,
393 if( dbus_error_is_set( &error ) )
395 msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
397 dbus_error_free( &error );
398 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
401 msg_Dbg( (vlc_object_t*) p_this, "Getting All properties" );
403 if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}", &dict ) )
404 return DBUS_HANDLER_RESULT_NEED_MEMORY;
406 ADD_PROPERTY( Identity, "s" );
407 ADD_PROPERTY( DesktopEntry, "s" );
408 ADD_PROPERTY( SupportedMimeTypes, "as" );
409 ADD_PROPERTY( SupportedUriSchemes, "as" );
410 ADD_PROPERTY( HasTrackList, "b" );
411 ADD_PROPERTY( CanQuit, "b" );
412 ADD_PROPERTY( CanSetFullscreen, "b" );
413 ADD_PROPERTY( Fullscreen, "b" );
414 ADD_PROPERTY( CanRaise, "b" );
416 if( !dbus_message_iter_close_container( &args, &dict ))
417 return DBUS_HANDLER_RESULT_NEED_MEMORY;
424 #define METHOD_MAPPING_BEGIN if( 0 ) {}
425 #define METHOD_FUNC( interface, method, function ) \
426 else if( dbus_message_is_method_call( p_from, interface, method ) )\
427 return function( p_conn, p_from, p_this )
428 #define METHOD_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
431 handle_root ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
434 METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "Get", GetProperty );
435 METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "Set", SetProperty );
436 METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "GetAll", GetAllProperties );
437 METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Quit", Quit );
438 METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Raise", Raise );
442 #undef METHOD_MAPPING_BEGIN
444 #undef METHOD_MAPPING_END
446 * PropertiesChangedSignal() synthetizes and sends the
447 * org.freedesktop.DBus.Properties.PropertiesChanged signal
450 #define PROPERTY_MAPPING_BEGIN if( 0 ) {}
451 #define PROPERTY_ENTRY( prop, signature ) \
452 else if( !strcmp( ppsz_properties[i], #prop ) ) \
454 if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_intf, \
455 &changed_properties, #prop, signature, Marshal##prop ) ) \
456 return DBUS_HANDLER_RESULT_NEED_MEMORY; \
458 #define PROPERTY_MAPPING_END else { return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
460 static DBusHandlerResult
461 PropertiesChangedSignal( intf_thread_t *p_intf,
462 vlc_dictionary_t *p_changed_properties )
464 DBusConnection *p_conn = p_intf->p_sys->p_conn;
465 DBusMessageIter changed_properties, invalidated_properties;
466 const char *psz_interface_name = DBUS_MPRIS_ROOT_INTERFACE;
467 char **ppsz_properties = NULL;
468 int i_properties = 0;
470 SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
471 DBUS_MPRIS_OBJECT_PATH,
472 "PropertiesChanged" );
475 ADD_STRING( &psz_interface_name );
477 if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
478 &changed_properties ) )
479 return DBUS_HANDLER_RESULT_NEED_MEMORY;
481 i_properties = vlc_dictionary_keys_count( p_changed_properties );
482 ppsz_properties = vlc_dictionary_all_keys( p_changed_properties );
484 if( unlikely(!ppsz_properties) )
486 dbus_message_iter_abandon_container( &args, &changed_properties );
487 return DBUS_HANDLER_RESULT_NEED_MEMORY;
490 for( int i = 0; i < i_properties; i++ )
492 PROPERTY_MAPPING_BEGIN
493 PROPERTY_ENTRY( Fullscreen, "b" )
496 free( ppsz_properties[i] );
499 if( !dbus_message_iter_close_container( &args, &changed_properties ) )
500 return DBUS_HANDLER_RESULT_NEED_MEMORY;
502 if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
503 &invalidated_properties ) )
504 return DBUS_HANDLER_RESULT_NEED_MEMORY;
506 if( !dbus_message_iter_close_container( &args, &invalidated_properties ) )
507 return DBUS_HANDLER_RESULT_NEED_MEMORY;
509 free( ppsz_properties );
514 /*****************************************************************************
515 * RootPropertiesChangedEmit: Emits the Seeked signal
516 *****************************************************************************/
517 int RootPropertiesChangedEmit( intf_thread_t *p_intf,
518 vlc_dictionary_t *p_changed_properties )
520 if( p_intf->p_sys->b_dead )
523 PropertiesChangedSignal( p_intf, p_changed_properties );