qml: fix scrollbar in NetworkHomeDisplay
[vlc.git] / modules / control / dbus / dbus_root.c
1 /*****************************************************************************
2  * dbus_root.c : dbus control module (mpris v2.2) - 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
8  *
9  * Authors:    Mirsal Ennaime <mirsal at mirsal fr>
10  *             Rafaël Carré <funman at videolanorg>
11  *             Alex Merry <dev at randomguy3 me uk>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_interface.h>
34 #include <vlc_vout.h>
35 #include <vlc_plugin.h>
36
37 #include <unistd.h>
38 #include <limits.h>
39
40 #include "dbus_root.h"
41 #include "dbus_common.h"
42
43 static const char ppsz_supported_uri_schemes[][9] = {
44     "file", "http", "https", "rtsp", "ftp", "mtp", "smb",
45     "mms", "mmsu", "mmst", "mmsh", "unsv", "itpc", "icyx", "rtmp", "rtp",
46     "dccp", "dvd", "vcd"
47 };
48
49 static const char ppsz_supported_mime_types[][26] = {
50     "audio/mpeg", "audio/x-mpeg",
51     "video/mpeg", "video/x-mpeg",
52     "video/mpeg-system", "video/x-mpeg-system",
53     "video/mp4",
54     "audio/mp4",
55     "video/x-msvideo",
56     "video/quicktime",
57     "application/ogg", "application/x-ogg",
58     "video/x-ms-asf",  "video/x-ms-asf-plugin",
59     "application/x-mplayer2",
60     "video/x-ms-wmv",
61     "video/x-google-vlc-plugin",
62     "audio/wav", "audio/x-wav",
63     "audio/3gpp",
64     "video/3gpp",
65     "audio/3gpp2",
66     "video/3gpp2",
67     "video/divx",
68     "video/flv", "video/x-flv",
69     "video/x-matroska",
70     "audio/x-matroska",
71     "application/xspf+xml"
72 };
73
74 static int
75 MarshalIdentity( intf_thread_t *p_intf, DBusMessageIter *container )
76 {
77     VLC_UNUSED( p_intf );
78     const char *psz_id = _("VLC media player");
79
80     if (!dbus_message_iter_append_basic( container, DBUS_TYPE_STRING, &psz_id ))
81         return VLC_ENOMEM;
82
83     return VLC_SUCCESS;
84 }
85
86 static int
87 MarshalCanSetFullscreen( intf_thread_t *p_intf, DBusMessageIter *container )
88 { VLC_UNUSED(p_intf);
89     dbus_bool_t b_ret = TRUE;
90     if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
91         return VLC_ENOMEM;
92     return VLC_SUCCESS;
93 }
94
95 static int
96 MarshalFullscreen( intf_thread_t *p_intf, DBusMessageIter *container )
97 {
98     dbus_bool_t b_fullscreen;
99     vlc_player_t *player = vlc_playlist_GetPlayer(p_intf->p_sys->playlist);
100     b_fullscreen = vlc_player_vout_IsFullscreen(player);
101     if (!dbus_message_iter_append_basic( container,
102             DBUS_TYPE_BOOLEAN, &b_fullscreen ))
103         return VLC_ENOMEM;
104     return VLC_SUCCESS;
105 }
106
107 DBUS_METHOD( FullscreenSet )
108 {
109     REPLY_INIT;
110     dbus_bool_t b_fullscreen;
111
112     if( VLC_SUCCESS != DemarshalSetPropertyValue( p_from, &b_fullscreen ) )
113         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
114
115     vlc_player_t *player = vlc_playlist_GetPlayer(PL);
116     vlc_player_vout_SetFullscreen(player, b_fullscreen);
117
118     REPLY_SEND;
119 }
120
121 static int
122 MarshalCanQuit( intf_thread_t *p_intf, DBusMessageIter *container )
123 {
124     VLC_UNUSED( p_intf );
125     const dbus_bool_t b_ret = TRUE;
126
127     if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
128         return VLC_ENOMEM;
129
130     return VLC_SUCCESS;
131 }
132
133 static int
134 MarshalCanRaise( intf_thread_t *p_intf, DBusMessageIter *container )
135 {
136     VLC_UNUSED( p_intf );
137     const dbus_bool_t b_ret = TRUE;
138
139     if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
140         return VLC_ENOMEM;
141
142     return VLC_SUCCESS;
143 }
144
145 static int
146 MarshalHasTrackList( intf_thread_t *p_intf, DBusMessageIter *container )
147 {
148     VLC_UNUSED( p_intf );
149     const dbus_bool_t b_ret = TRUE;
150
151     if (!dbus_message_iter_append_basic( container, DBUS_TYPE_BOOLEAN, &b_ret ))
152         return VLC_ENOMEM;
153
154     return VLC_SUCCESS;
155 }
156
157 static int
158 MarshalDesktopEntry( intf_thread_t *p_intf, DBusMessageIter *container )
159 {
160     VLC_UNUSED( p_intf );
161     const char* psz_ret = PACKAGE;
162
163     if (!dbus_message_iter_append_basic( container, DBUS_TYPE_STRING, &psz_ret ))
164         return VLC_ENOMEM;
165
166     return VLC_SUCCESS;
167 }
168
169 static int
170 MarshalSupportedMimeTypes( intf_thread_t *p_intf, DBusMessageIter *container )
171 {
172     VLC_UNUSED( p_intf );
173     DBusMessageIter ret;
174
175     size_t i_len = sizeof( ppsz_supported_mime_types ) /
176         sizeof( *ppsz_supported_mime_types );
177
178     if( !dbus_message_iter_open_container( container,
179                                            DBUS_TYPE_ARRAY, "s",
180                                            &ret ) )
181         return VLC_ENOMEM;
182
183     for( size_t i = 0; i < i_len; ++i )
184     {
185         const char* const psz_mime_type = ppsz_supported_mime_types[i];
186
187         if( !dbus_message_iter_append_basic( &ret, DBUS_TYPE_STRING,
188                                              &psz_mime_type ) )
189             return VLC_ENOMEM;
190     }
191
192     if( !dbus_message_iter_close_container( container, &ret ) )
193         return VLC_ENOMEM;
194
195     return VLC_SUCCESS;
196 }
197
198 static int
199 MarshalSupportedUriSchemes( intf_thread_t *p_intf, DBusMessageIter *container )
200 {
201     VLC_UNUSED( p_intf );
202     DBusMessageIter ret;
203
204     size_t i_len = sizeof( ppsz_supported_uri_schemes ) /
205         sizeof( *ppsz_supported_uri_schemes );
206
207     if( !dbus_message_iter_open_container( container,
208                                            DBUS_TYPE_ARRAY, "s",
209                                            &ret ) )
210         return VLC_ENOMEM;
211
212     for( size_t i = 0; i < i_len; ++i )
213     {
214         const char* const psz_scheme = ppsz_supported_uri_schemes[i];
215
216         if( !dbus_message_iter_append_basic( &ret, DBUS_TYPE_STRING,
217                                              &psz_scheme ) )
218             return VLC_ENOMEM;
219     }
220
221     if( !dbus_message_iter_close_container( container, &ret ) )
222         return VLC_ENOMEM;
223
224     return VLC_SUCCESS;
225 }
226
227 DBUS_METHOD( Quit )
228 { /* exits vlc */
229     REPLY_INIT;
230     libvlc_Quit(vlc_object_instance(INTF));
231     REPLY_SEND;
232 }
233
234 DBUS_METHOD( Raise )
235 {/* shows vlc's main window */
236     REPLY_INIT;
237     var_TriggerCallback(vlc_object_instance(INTF), "intf-show" );
238     REPLY_SEND;
239 }
240
241 #define PROPERTY_MAPPING_BEGIN
242 #define PROPERTY_GET_FUNC( prop, signature ) \
243     if( !strcmp( psz_property_name,  #prop ) ) { \
244         if( !dbus_message_iter_open_container( &args, DBUS_TYPE_VARIANT, signature, &v ) ) \
245             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
246         if( VLC_SUCCESS != Marshal##prop( p_this, &v ) ) { \
247             dbus_message_iter_abandon_container( &args, &v ); \
248             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
249         } \
250         if( !dbus_message_iter_close_container( &args, &v ) ) \
251             return DBUS_HANDLER_RESULT_NEED_MEMORY; \
252     } else
253 #define PROPERTY_SET_FUNC( prop ) \
254     if( !strcmp( psz_property_name,  #prop ) ) \
255         return prop##Set( p_conn, p_from, p_this ); \
256     else
257 #define PROPERTY_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
258
259 DBUS_METHOD( GetProperty )
260 {
261     DBusError error;
262
263     char *psz_interface_name = NULL;
264     char *psz_property_name  = NULL;
265
266     dbus_error_init( &error );
267     dbus_message_get_args( p_from, &error,
268             DBUS_TYPE_STRING, &psz_interface_name,
269             DBUS_TYPE_STRING, &psz_property_name,
270             DBUS_TYPE_INVALID );
271
272     if( dbus_error_is_set( &error ) )
273     {
274         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
275                                          error.message );
276         dbus_error_free( &error );
277         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
278     }
279
280     msg_Dbg( (vlc_object_t*) p_this, "Getting property %s",
281                                      psz_property_name );
282
283     if( strcmp( psz_interface_name, DBUS_MPRIS_ROOT_INTERFACE ) ) {
284         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
285     }
286
287     REPLY_INIT;
288     OUT_ARGUMENTS;
289     DBusMessageIter v;
290
291     PROPERTY_MAPPING_BEGIN
292     PROPERTY_GET_FUNC( Identity,            "s" )
293     PROPERTY_GET_FUNC( CanSetFullscreen,    "b" )
294     PROPERTY_GET_FUNC( Fullscreen,          "b" )
295     PROPERTY_GET_FUNC( CanQuit,             "b" )
296     PROPERTY_GET_FUNC( CanRaise,            "b" )
297     PROPERTY_GET_FUNC( HasTrackList,        "b" )
298     PROPERTY_GET_FUNC( DesktopEntry,        "s" )
299     PROPERTY_GET_FUNC( SupportedMimeTypes,  "as" )
300     PROPERTY_GET_FUNC( SupportedUriSchemes, "as" )
301     PROPERTY_MAPPING_END
302
303     REPLY_SEND;
304 }
305
306 DBUS_METHOD( SetProperty )
307 {
308     DBusError error;
309
310     char *psz_interface_name = NULL;
311     char *psz_property_name  = NULL;
312
313     dbus_error_init( &error );
314     dbus_message_get_args( p_from, &error,
315             DBUS_TYPE_STRING, &psz_interface_name,
316             DBUS_TYPE_STRING, &psz_property_name,
317             DBUS_TYPE_INVALID );
318
319     if( dbus_error_is_set( &error ) )
320     {
321         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
322                                         error.message );
323         dbus_error_free( &error );
324         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
325     }
326
327     PROPERTY_MAPPING_BEGIN
328     PROPERTY_SET_FUNC( Fullscreen )
329     PROPERTY_MAPPING_END
330 }
331
332 #undef PROPERTY_MAPPING_BEGIN
333 #undef PROPERTY_GET_FUNC
334 #undef PROPERTY_SET_FUNC
335 #undef PROPERTY_MAPPING_END
336
337 #define ADD_PROPERTY( prop, signature ) \
338     if( VLC_SUCCESS != AddProperty( (intf_thread_t*) p_this, \
339                 &dict, #prop, signature, Marshal##prop ) ) { \
340         dbus_message_iter_abandon_container( &args, &dict ); \
341         return VLC_ENOMEM; \
342     }
343
344 DBUS_METHOD( GetAllProperties )
345 {
346     REPLY_INIT;
347     OUT_ARGUMENTS;
348
349     DBusError error;
350     DBusMessageIter dict;
351
352     char *const psz_interface_name = NULL;
353
354     dbus_error_init( &error );
355     dbus_message_get_args( p_from, &error,
356             DBUS_TYPE_STRING, &psz_interface_name,
357             DBUS_TYPE_INVALID );
358
359     if( dbus_error_is_set( &error ) )
360     {
361         msg_Err( (vlc_object_t*) p_this, "D-Bus message reading : %s",
362                                          error.message );
363         dbus_error_free( &error );
364         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
365     }
366
367     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}", &dict ) )
368         return DBUS_HANDLER_RESULT_NEED_MEMORY;
369
370     ADD_PROPERTY( Identity,            "s"  );
371     ADD_PROPERTY( DesktopEntry,        "s"  );
372     ADD_PROPERTY( SupportedMimeTypes,  "as" );
373     ADD_PROPERTY( SupportedUriSchemes, "as" );
374     ADD_PROPERTY( HasTrackList,        "b"  );
375     ADD_PROPERTY( CanQuit,             "b"  );
376     ADD_PROPERTY( CanSetFullscreen,    "b"  );
377     ADD_PROPERTY( Fullscreen,          "b"  );
378     ADD_PROPERTY( CanRaise,            "b"  );
379
380     if( !dbus_message_iter_close_container( &args, &dict ))
381         return DBUS_HANDLER_RESULT_NEED_MEMORY;
382
383     REPLY_SEND;
384 }
385
386 #undef ADD_PROPERTY
387
388 #define METHOD_MAPPING_BEGIN if( 0 ) {}
389 #define METHOD_FUNC( interface, method, function ) \
390     else if( dbus_message_is_method_call( p_from, interface, method ) )\
391         return function( p_conn, p_from, p_this )
392 #define METHOD_MAPPING_END return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
393
394 DBusHandlerResult
395 handle_root ( DBusConnection *p_conn, DBusMessage *p_from, void *p_this )
396 {
397     METHOD_MAPPING_BEGIN
398     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "Get",          GetProperty );
399     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "Set",          SetProperty );
400     METHOD_FUNC( DBUS_INTERFACE_PROPERTIES, "GetAll",       GetAllProperties );
401     METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Quit",         Quit );
402     METHOD_FUNC( DBUS_MPRIS_ROOT_INTERFACE, "Raise",        Raise );
403     METHOD_MAPPING_END
404 }
405
406 #undef METHOD_MAPPING_BEGIN
407 #undef METHOD_FUNC
408 #undef METHOD_MAPPING_END
409 /**
410  * PropertiesChangedSignal() synthetizes and sends the
411  * org.freedesktop.DBus.Properties.PropertiesChanged signal
412  */
413 static DBusHandlerResult
414 PropertiesChangedSignal( intf_thread_t    *p_intf,
415                          vlc_dictionary_t *p_changed_properties )
416 {
417     DBusConnection  *p_conn = p_intf->p_sys->p_conn;
418     DBusMessageIter changed_properties, invalidated_properties;
419     const char *psz_interface_name = DBUS_MPRIS_ROOT_INTERFACE;
420
421     SIGNAL_INIT( DBUS_INTERFACE_PROPERTIES,
422                  DBUS_MPRIS_OBJECT_PATH,
423                  "PropertiesChanged" );
424
425     OUT_ARGUMENTS;
426     ADD_STRING( &psz_interface_name );
427
428     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "{sv}",
429                                            &changed_properties ) )
430         return DBUS_HANDLER_RESULT_NEED_MEMORY;
431
432     if( vlc_dictionary_has_key( p_changed_properties, "Fullscreen" ) )
433     {
434         if( AddProperty( p_intf, &changed_properties, "Fullscreen", "b",
435                      MarshalFullscreen ) != VLC_SUCCESS )
436         {
437             dbus_message_iter_abandon_container( &args, &changed_properties );
438             return DBUS_HANDLER_RESULT_NEED_MEMORY;
439         }
440     }
441
442     if( !dbus_message_iter_close_container( &args, &changed_properties ) )
443         return DBUS_HANDLER_RESULT_NEED_MEMORY;
444
445     if( !dbus_message_iter_open_container( &args, DBUS_TYPE_ARRAY, "s",
446                                            &invalidated_properties ) )
447         return DBUS_HANDLER_RESULT_NEED_MEMORY;
448
449     if( !dbus_message_iter_close_container( &args, &invalidated_properties ) )
450         return DBUS_HANDLER_RESULT_NEED_MEMORY;
451
452     SIGNAL_SEND;
453 }
454
455 /*****************************************************************************
456  * RootPropertiesChangedEmit: Emits the Seeked signal
457  *****************************************************************************/
458 int RootPropertiesChangedEmit( intf_thread_t    *p_intf,
459                                vlc_dictionary_t *p_changed_properties )
460 {
461     if( p_intf->p_sys->b_dead )
462         return VLC_SUCCESS;
463
464     PropertiesChangedSignal( p_intf, p_changed_properties );
465     return VLC_SUCCESS;
466 }