]> git.sesse.net Git - vlc/blob - modules/misc/inhibit.c
OpenCV example: move to C++ and opencv2 APIs
[vlc] / modules / misc / inhibit.c
1 /*****************************************************************************
2  * inhibit.c : prevents the computer from suspending when VLC is playing
3  *****************************************************************************
4  * Copyright © 2007 Rafaël Carré
5  * $Id$
6  *
7  * Author: Rafaël Carré <funman@videolanorg>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*
25  * Based on freedesktop Power Management Specification version 0.2
26  * http://people.freedesktop.org/~hughsient/temp/power-management-spec-0.2.html
27  */
28
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include <vlc_input.h>
40 #include <vlc_interface.h>
41 #include <vlc_playlist.h>
42
43 #include <dbus/dbus.h>
44
45 enum {
46     FREEDESKTOP = 0, /* as used by KDE and gnome <= 2.26 */
47     GNOME       = 1, /* as used by gnome > 2.26 */
48 };
49
50 static const char *dbus_service[] = {
51     [FREEDESKTOP]   = "org.freedesktop.PowerManagement",
52     [GNOME]         = "org.gnome.SessionManager",
53 };
54
55 static const char *dbus_path[] = {
56     [FREEDESKTOP]   = "/org/freedesktop/PowerManagement",
57     [GNOME]         = "/org/gnome/SessionManager",
58 };
59
60 static const char *dbus_interface[] = {
61     [FREEDESKTOP]   = "org.freedesktop.PowerManagement.Inhibit",
62     [GNOME]         = "org.gnome.SessionManager",
63 };
64
65 static const char *dbus_uninhibit_method[] = {
66     [FREEDESKTOP]   = "UnInhibit",
67     [GNOME]         = "Uninhibit",
68 };
69
70
71 /*****************************************************************************
72  * Local prototypes
73  !*****************************************************************************/
74 static int  Activate     ( vlc_object_t * );
75 static void Deactivate   ( vlc_object_t * );
76
77 static void UnInhibit( intf_thread_t *p_intf, int type );
78
79 static int InputChange( vlc_object_t *, const char *,
80                         vlc_value_t, vlc_value_t, void * );
81 static int StateChange( vlc_object_t *, const char *,
82                         vlc_value_t, vlc_value_t, void * );
83
84 struct intf_sys_t
85 {
86     playlist_t      *p_playlist;
87     vlc_object_t    *p_input;
88     DBusConnection  *p_conn;
89     dbus_uint32_t   i_cookie[2];
90 };
91
92 /*****************************************************************************
93  * Module descriptor
94  *****************************************************************************/
95 vlc_module_begin ()
96     set_description( N_("Power Management Inhibitor") )
97     set_capability( "interface", 0 )
98     set_callbacks( Activate, Deactivate )
99 vlc_module_end ()
100
101 /*****************************************************************************
102  * Activate: initialize and create stuff
103  *****************************************************************************/
104 static int Activate( vlc_object_t *p_this )
105 {
106     intf_thread_t *p_intf = (intf_thread_t*)p_this;
107     intf_sys_t *p_sys;
108     DBusError     error;
109
110     p_sys = p_intf->p_sys = (intf_sys_t *) calloc( 1, sizeof( intf_sys_t ) );
111     if( !p_sys )
112         return VLC_ENOMEM;
113
114     p_sys->i_cookie[FREEDESKTOP] = 0;
115     p_sys->i_cookie[GNOME] = 0;
116     p_sys->p_input = NULL;
117
118     dbus_error_init( &error );
119
120     /* connect privately to the session bus
121      * the connection will not be shared with other vlc modules which use dbus,
122      * thus avoiding a whole class of concurrency issues */
123     p_sys->p_conn = dbus_bus_get_private( DBUS_BUS_SESSION, &error );
124     if( !p_sys->p_conn )
125     {
126         msg_Err( p_this, "Failed to connect to the D-Bus session daemon: %s",
127                 error.message );
128         dbus_error_free( &error );
129         free( p_sys );
130         return VLC_EGENERIC;
131     }
132
133     p_sys->p_playlist = pl_Get( p_intf );
134     var_AddCallback( p_sys->p_playlist, "item-current", InputChange, p_intf );
135     return VLC_SUCCESS;
136 }
137
138 /*****************************************************************************
139  * Deactivate: uninitialize and cleanup
140  *****************************************************************************/
141 static void Deactivate( vlc_object_t *p_this )
142 {
143     intf_thread_t *p_intf = (intf_thread_t*)p_this;
144     intf_sys_t *p_sys = p_intf->p_sys;
145
146     var_DelCallback( p_sys->p_playlist, "item-current", InputChange, p_intf );
147
148     if( p_sys->p_input ) /* Do delete "state" after "item-changed"! */
149     {
150         var_DelCallback( p_sys->p_input, "state", StateChange, p_intf );
151         vlc_object_release( p_sys->p_input );
152     }
153
154     if( p_sys->i_cookie[FREEDESKTOP] )
155         UnInhibit( p_intf, FREEDESKTOP );
156     if( p_sys->i_cookie[GNOME] )
157         UnInhibit( p_intf, GNOME );
158
159     /* The dbus connection is private,
160      * so we are responsible for closing it */
161     dbus_connection_close( p_sys->p_conn );
162     dbus_connection_unref( p_sys->p_conn );
163
164     free( p_sys );
165 }
166
167 /*****************************************************************************
168  * Inhibit: Notify the power management daemon that it shouldn't suspend
169  * the computer because of inactivity
170  *****************************************************************************/
171 static void Inhibit( intf_thread_t *p_intf, int type )
172 {
173     intf_sys_t *p_sys = p_intf->p_sys;
174
175     DBusMessage *msg = dbus_message_new_method_call(
176         dbus_service[type], dbus_path[type], dbus_interface[type], "Inhibit" );
177     if( unlikely(msg == NULL) )
178         return;
179
180     const char *app = PACKAGE;
181     const char *reason = _("Playing some media.");
182
183     p_sys->i_cookie[type] = 0;
184
185     dbus_bool_t ret;
186     dbus_uint32_t xid = 0; // FIXME?
187     dbus_uint32_t flags = 8 /* Inhibit suspending the session or computer */
188                         | 4;/* Inhibit the session being marked as idle */
189     switch( type ) {
190     case FREEDESKTOP:
191         ret = dbus_message_append_args( msg, DBUS_TYPE_STRING, &app,
192                                         DBUS_TYPE_STRING, &reason,
193                                         DBUS_TYPE_INVALID );
194         break;
195     case GNOME:
196     default:
197         ret = dbus_message_append_args( msg, DBUS_TYPE_STRING, &app,
198                                         DBUS_TYPE_UINT32, &xid,
199                                         DBUS_TYPE_STRING, &reason,
200                                         DBUS_TYPE_UINT32, &flags,
201                                         DBUS_TYPE_INVALID );
202         break;
203     }
204
205     if( !ret )
206     {
207         dbus_message_unref( msg );
208         return;
209     }
210
211     /* blocks 50ms maximum */
212     DBusMessage *reply;
213
214     reply = dbus_connection_send_with_reply_and_block( p_sys->p_conn, msg,
215                                                        50, NULL );
216     dbus_message_unref( msg );
217     if( reply == NULL )
218         /* g-p-m is not active, or too slow. Better luck next time? */
219         return;
220
221     /* extract the cookie from the reply */
222     dbus_uint32_t i_cookie;
223
224     if( dbus_message_get_args( reply, NULL,
225                                DBUS_TYPE_UINT32, &i_cookie,
226                                DBUS_TYPE_INVALID ) )
227         p_sys->i_cookie[type] = i_cookie;
228
229     dbus_message_unref( reply );
230 }
231
232 /*****************************************************************************
233  * UnInhibit: Notify the power management daemon that we aren't active anymore
234  *****************************************************************************/
235 static void UnInhibit( intf_thread_t *p_intf, int type )
236 {
237     intf_sys_t *p_sys = p_intf->p_sys;
238
239     DBusMessage *msg = dbus_message_new_method_call( dbus_service[type],
240             dbus_path[type], dbus_interface[type], dbus_uninhibit_method[type] );
241     if( unlikely(msg == NULL) )
242         return;
243
244     dbus_uint32_t i_cookie = p_sys->i_cookie[type];
245     if( dbus_message_append_args( msg, DBUS_TYPE_UINT32, &i_cookie,
246                                        DBUS_TYPE_INVALID )
247      && dbus_connection_send( p_sys->p_conn, msg, NULL ) )
248     {
249         dbus_connection_flush( p_sys->p_conn );
250         p_sys->i_cookie[type] = 0;
251     }
252     dbus_message_unref( msg );
253 }
254
255
256 static int StateChange( vlc_object_t *p_input, const char *var,
257                         vlc_value_t prev, vlc_value_t value, void *data )
258 {
259     intf_thread_t *p_intf = data;
260     intf_sys_t *p_sys = p_intf->p_sys;
261     const int old = prev.i_int, cur = value.i_int;
262
263     if( ( old == PLAYING_S ) == ( cur == PLAYING_S ) )
264         return VLC_SUCCESS; /* No interesting change */
265
266     if( cur == PLAYING_S ) {
267         if (p_sys->i_cookie[FREEDESKTOP] == 0)
268             Inhibit( p_intf, FREEDESKTOP );
269         if (p_sys->i_cookie[GNOME] == 0)
270             Inhibit( p_intf, GNOME );
271     }
272     else {
273         if (p_sys->i_cookie[FREEDESKTOP] != 0)
274             UnInhibit( p_intf, FREEDESKTOP );
275         if (p_sys->i_cookie[GNOME] != 0)
276             UnInhibit( p_intf, GNOME );
277     }
278
279     (void)p_input; (void)var; (void)prev;
280     return VLC_SUCCESS;
281 }
282
283 static int InputChange( vlc_object_t *p_playlist, const char *var,
284                         vlc_value_t prev, vlc_value_t value, void *data )
285 {
286     intf_thread_t *p_intf = data;
287     intf_sys_t *p_sys = p_intf->p_sys;
288
289     if( p_sys->p_input )
290     {
291         var_DelCallback( p_sys->p_input, "state", StateChange, p_intf );
292         vlc_object_release( p_sys->p_input );
293     }
294     p_sys->p_input = VLC_OBJECT(playlist_CurrentInput( p_sys->p_playlist ));
295     if( p_sys->p_input )
296     {
297         Inhibit( p_intf, FREEDESKTOP );
298         Inhibit( p_intf, GNOME );
299
300         var_AddCallback( p_sys->p_input, "state", StateChange, p_intf );
301     }
302
303     (void)var; (void)prev; (void)value; (void)p_playlist;
304     return VLC_SUCCESS;
305 }