1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2005-2007 Richard Hughes <richard@hughsie.com>
4 * Copyright (C) 2012-2021 MATE Developers
5 *
6 * Taken in part from:
7 * - lshal (C) 2003 David Zeuthen, <david@fubar.dk>
8 * - notibat (C) 2004 Benjamin Kahn, <xkahn@zoned.net>
9 *
10 * Licensed under the GNU General Public License Version 2
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #include "config.h"
28
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <locale.h>
34 #include <glib.h>
35 #include <glib/gi18n.h>
36 #include <gtk/gtk.h>
37 #include <dbus/dbus-glib.h>
38 #include <dbus/dbus-glib-lowlevel.h>
39
40 #include "gpm-icon-names.h"
41 #include "gpm-common.h"
42 #include "gpm-manager.h"
43 #include "gpm-session.h"
44
45 #include "org.mate.PowerManager.h"
46
47 /**
48 * gpm_object_register:
49 * @connection: What we want to register to
50 * @object: The GObject we want to register
51 *
52 * Register org.mate.PowerManager on the session bus.
53 * This function MUST be called before DBUS service will work.
54 *
55 * Return value: success
56 **/
57 static gboolean
gpm_object_register(DBusGConnection * connection,GObject * object)58 gpm_object_register (DBusGConnection *connection,
59 GObject *object)
60 {
61 DBusGProxy *bus_proxy = NULL;
62 GError *error = NULL;
63 guint request_name_result;
64 gboolean ret;
65
66 bus_proxy = dbus_g_proxy_new_for_name (connection,
67 DBUS_SERVICE_DBUS,
68 DBUS_PATH_DBUS,
69 DBUS_INTERFACE_DBUS);
70
71 ret = dbus_g_proxy_call (bus_proxy, "RequestName", &error,
72 G_TYPE_STRING, GPM_DBUS_SERVICE,
73 G_TYPE_UINT, 0,
74 G_TYPE_INVALID,
75 G_TYPE_UINT, &request_name_result,
76 G_TYPE_INVALID);
77 if (error) {
78 g_debug ("ERROR: %s", error->message);
79 g_error_free (error);
80 }
81 if (!ret) {
82 /* abort as the DBUS method failed */
83 g_warning ("RequestName failed!");
84 return FALSE;
85 }
86
87 /* free the bus_proxy */
88 g_object_unref (G_OBJECT (bus_proxy));
89
90 /* already running */
91 if (request_name_result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
92 return FALSE;
93 }
94
95 dbus_g_object_type_install_info (GPM_TYPE_MANAGER, &dbus_glib_gpm_manager_object_info);
96 dbus_g_error_domain_register (GPM_MANAGER_ERROR, NULL, GPM_MANAGER_TYPE_ERROR);
97 dbus_g_connection_register_g_object (connection, GPM_DBUS_PATH, object);
98
99 return TRUE;
100 }
101
102 /**
103 * timed_exit_cb:
104 * @loop: The main loop
105 *
106 * Exits the main loop, which is helpful for valgrinding g-p-m.
107 *
108 * Return value: FALSE, as we don't want to repeat this action.
109 **/
110 static gboolean
timed_exit_cb(GMainLoop * loop)111 timed_exit_cb (GMainLoop *loop)
112 {
113 g_main_loop_quit (loop);
114 return FALSE;
115 }
116
117 /**
118 * gpm_main_stop_cb:
119 **/
120 static void
gpm_main_stop_cb(GpmSession * session,GMainLoop * loop)121 gpm_main_stop_cb (GpmSession *session, GMainLoop *loop)
122 {
123 g_main_loop_quit (loop);
124 }
125
126 /**
127 * gpm_main_query_end_session_cb:
128 **/
129 static void
gpm_main_query_end_session_cb(GpmSession * session,guint flags,GMainLoop * loop)130 gpm_main_query_end_session_cb (GpmSession *session, guint flags, GMainLoop *loop)
131 {
132 /* just send response */
133 gpm_session_end_session_response (session, TRUE, NULL);
134 }
135
136 /**
137 * gpm_main_end_session_cb:
138 **/
139 static void
gpm_main_end_session_cb(GpmSession * session,guint flags,GMainLoop * loop)140 gpm_main_end_session_cb (GpmSession *session, guint flags, GMainLoop *loop)
141 {
142 /* send response */
143 gpm_session_end_session_response (session, TRUE, NULL);
144
145 /* exit loop, will unref manager */
146 g_main_loop_quit (loop);
147 }
148
149 /**
150 * main:
151 **/
152 int
main(int argc,char * argv[])153 main (int argc, char *argv[])
154 {
155 GMainLoop *loop;
156 DBusGConnection *system_connection;
157 DBusGConnection *session_connection;
158 gboolean version = FALSE;
159 gboolean timed_exit = FALSE;
160 gboolean immediate_exit = FALSE;
161 GpmSession *session = NULL;
162 GpmManager *manager = NULL;
163 GError *error = NULL;
164 GOptionContext *context;
165 gint ret;
166 guint timer_id;
167
168 const GOptionEntry options[] = {
169 { "version", '\0', 0, G_OPTION_ARG_NONE, &version,
170 N_("Show version of installed program and exit"), NULL },
171 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
172 N_("Exit after a small delay (for debugging)"), NULL },
173 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
174 N_("Exit after the manager has loaded (for debugging)"), NULL },
175 { NULL}
176 };
177
178 setlocale (LC_ALL, "");
179 bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
180 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
181 textdomain (GETTEXT_PACKAGE);
182
183 dbus_g_thread_init ();
184
185 context = g_option_context_new (N_("MATE Power Manager"));
186 /* TRANSLATORS: program name, a simple app to view pending updates */
187 g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
188 g_option_context_set_translation_domain(context, GETTEXT_PACKAGE);
189 g_option_context_set_summary (context, _("MATE Power Manager"));
190 g_option_context_parse (context, &argc, &argv, NULL);
191
192 if (version) {
193 g_print ("Version %s\n", VERSION);
194 goto unref_program;
195 }
196
197 dbus_g_thread_init ();
198
199 gtk_init (&argc, &argv);
200
201 g_debug ("MATE %s %s", GPM_NAME, VERSION);
202
203 /* check dbus connections, exit if not valid */
204 system_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
205 if (error) {
206 g_warning ("%s", error->message);
207 g_error_free (error);
208 g_error ("This program cannot start until you start "
209 "the dbus system service.\n"
210 "It is <b>strongly recommended</b> you reboot "
211 "your computer after starting this service.");
212 }
213
214 session_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
215 if (error) {
216 g_warning ("%s", error->message);
217 g_error_free (error);
218 g_error ("This program cannot start until you start the "
219 "dbus session service.\n\n"
220 "This is usually started automatically in X "
221 "or mate startup when you start a new session.");
222 }
223
224 /* add application specific icons to search path */
225 gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
226 GPM_ICONS_DATA);
227
228 loop = g_main_loop_new (NULL, FALSE);
229
230 /* optionally register with the session */
231 session = gpm_session_new ();
232 g_signal_connect (session, "stop", G_CALLBACK (gpm_main_stop_cb), loop);
233 g_signal_connect (session, "query-end-session", G_CALLBACK (gpm_main_query_end_session_cb), loop);
234 g_signal_connect (session, "end-session", G_CALLBACK (gpm_main_end_session_cb), loop);
235 gpm_session_register_client (session, "mate-power-manager", getenv ("DESKTOP_AUTOSTART_ID"));
236
237 /* create a new gui object */
238 manager = gpm_manager_new ();
239
240 if (!gpm_object_register (session_connection, G_OBJECT (manager))) {
241 g_error ("%s is already running in this session.", GPM_NAME);
242 goto unref_program;
243 }
244
245 /* register to be a policy agent, just like kpackagekit does */
246 ret = dbus_bus_request_name(dbus_g_connection_get_connection(system_connection),
247 "org.freedesktop.Policy.Power",
248 DBUS_NAME_FLAG_REPLACE_EXISTING, NULL);
249 switch (ret) {
250 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
251 g_debug ("Successfully acquired interface org.freedesktop.Policy.Power.");
252 break;
253 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
254 g_debug ("Queued for interface org.freedesktop.Policy.Power.");
255 break;
256 default:
257 break;
258 };
259
260 /* Only timeout and close the mainloop if we have specified it
261 * on the command line */
262 if (timed_exit) {
263 timer_id = g_timeout_add_seconds (20, (GSourceFunc) timed_exit_cb, loop);
264 g_source_set_name_by_id (timer_id, "[GpmMain] timed-exit");
265 }
266
267 if (immediate_exit == FALSE) {
268 g_main_loop_run (loop);
269 }
270
271 g_main_loop_unref (loop);
272
273 g_object_unref (session);
274 g_object_unref (manager);
275 unref_program:
276 g_option_context_free (context);
277 return 0;
278 }
279