]> git.sesse.net Git - vlc/blob - modules/misc/inhibit/power.c
9ca10f812f5a292a501e7466890d6881f088b2d1
[vlc] / modules / misc / inhibit / power.c
1 /*****************************************************************************
2  * power.c : prevents the computer from suspending when VLC is playing
3  *****************************************************************************
4  * Copyright © 2009-2011 Rémi Denis-Courmont
5  * Copyright © 2007-2012 Rafaël Carré
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20  *****************************************************************************/
21
22 /*
23  * Based on freedesktop Power Management Specification version 0.2
24  * http://people.freedesktop.org/~hughsient/temp/power-management-spec-0.2.html
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_inhibit.h>
34 #include <dbus/dbus.h>
35
36 enum vlc_inhibit_api
37 {
38     FREEDESKTOP, /* KDE and GNOME <= 2.26 */
39     GNOME, /**< GNOME 2.26..3.4 */
40 };
41
42 static const char dbus_service[][32] =
43 {
44     [FREEDESKTOP] = "org.freedesktop.PowerManagement",
45     [GNOME]       = "org.gnome.SessionManager",
46 };
47
48 static const char dbus_path[][33] =
49 {
50     [FREEDESKTOP] = "/org/freedesktop/PowerManagement",
51     [GNOME]       = "/org/gnome/SessionManager",
52 };
53
54 static const char dbus_interface[][40] =
55 {
56     [FREEDESKTOP] = "org.freedesktop.PowerManagement.Inhibit",
57     [GNOME]       = "org.gnome.SessionManager",
58 };
59
60 static const char dbus_method_uninhibit[][10] =
61 {
62     [FREEDESKTOP] = "UnInhibit",
63     [GNOME]       = "Uninhibit",
64 };
65
66 struct vlc_inhibit_sys
67 {
68     DBusConnection *conn;
69     dbus_uint32_t cookie[2];
70 };
71
72 static void InhibitAPI(vlc_inhibit_t *ih, unsigned flags,
73                        enum vlc_inhibit_api type)
74 {
75     vlc_inhibit_sys_t *sys = ih->p_sys;
76     DBusConnection *conn = sys->conn;
77
78     const char *method = flags ? "Inhibit" : dbus_method_uninhibit[type];
79     dbus_bool_t ret;
80
81     DBusMessage *msg = dbus_message_new_method_call(dbus_service[type],
82                                 dbus_path[type], dbus_interface[type], method);
83     if (unlikely(msg == NULL))
84         return;
85
86     if (flags) {
87         const char *app = PACKAGE;
88         const char *reason = N_("Playing some media.");
89
90         switch (type)
91         {
92             case FREEDESKTOP:
93                 ret = dbus_message_append_args(msg, DBUS_TYPE_STRING, &app,
94                                                     DBUS_TYPE_STRING, &reason,
95                                                     DBUS_TYPE_INVALID);
96                 break;
97             case GNOME:
98             {
99                 dbus_uint32_t xid = 0; // FIXME ?
100                 dbus_uint32_t gflags =
101                    ((flags & VLC_INHIBIT_SUSPEND) ? 8 : 0) |
102                    ((flags & VLC_INHIBIT_DISPLAY) ? 4 : 0);
103
104                 ret = dbus_message_append_args(msg, DBUS_TYPE_STRING, &app,
105                                                     DBUS_TYPE_UINT32, &xid,
106                                                     DBUS_TYPE_STRING, &reason,
107                                                     DBUS_TYPE_UINT32, &gflags,
108                                                     DBUS_TYPE_INVALID);
109                 break;
110             }
111         }
112     } else {
113         if (sys->cookie[type])
114             ret = dbus_message_append_args(msg, DBUS_TYPE_UINT32,
115                                                             &sys->cookie[type],
116                                                 DBUS_TYPE_INVALID);
117         else
118             ret = false;
119     }
120
121     if (!ret)
122         goto giveup;
123
124     if (flags) { /* read reply */
125         DBusMessage *reply = dbus_connection_send_with_reply_and_block(
126                                                           conn, msg, 50, NULL);
127         if (unlikely(reply == NULL))
128             goto giveup; /* no reponse?! */
129
130         if (!dbus_message_get_args(reply, NULL,
131                                    DBUS_TYPE_UINT32, &sys->cookie[type],
132                                    DBUS_TYPE_INVALID))
133             sys->cookie[type] = 0;
134
135         dbus_message_unref(reply);
136     } else { /* just send and flush */
137         if (dbus_connection_send (conn, msg, NULL)) {
138             sys->cookie[type] = 0;
139             dbus_connection_flush(conn);
140         }
141     }
142 giveup:
143     dbus_message_unref(msg);
144 }
145
146 static void Inhibit (vlc_inhibit_t *ih, unsigned flags)
147 {
148     for (int type = 0; type < 2; type++)
149         InhibitAPI (ih, flags, type);
150 }
151
152 static int Open (vlc_object_t *obj)
153 {
154     vlc_inhibit_t *ih = (vlc_inhibit_t *)obj;
155     vlc_inhibit_sys_t *sys = malloc (sizeof (*sys));
156     if (unlikely(sys == NULL))
157         return VLC_ENOMEM;
158
159     DBusError err;
160
161     dbus_error_init (&err);
162     sys->conn = dbus_bus_get_private (DBUS_BUS_SESSION, &err);
163     if (sys->conn == NULL)
164     {
165         msg_Err (obj, "cannot connect to session bus: %s", err.message);
166         dbus_error_free (&err);
167         free (sys);
168         return VLC_EGENERIC;
169     }
170     sys->cookie[0] = 0;
171     sys->cookie[1] = 0;
172
173     ih->p_sys = sys;
174     ih->inhibit = Inhibit;
175     return VLC_SUCCESS;
176 }
177
178 static void Close (vlc_object_t *obj)
179 {
180     vlc_inhibit_t *ih = (vlc_inhibit_t *)obj;
181     vlc_inhibit_sys_t *sys = ih->p_sys;
182
183     dbus_connection_close (sys->conn);
184     dbus_connection_unref (sys->conn);
185     free (sys);
186 }
187
188 /*
189  * Module descriptor
190  */
191 vlc_module_begin ()
192     set_shortname (N_("Power"))
193     set_description (N_("Inhibits power suspend and session idle timeout."))
194     set_category (CAT_ADVANCED)
195     set_subcategory (SUBCAT_ADVANCED_MISC)
196     set_capability ("inhibit", 20)
197     set_callbacks (Open, Close)
198 vlc_module_end ()