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