1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2004-2006 William Jon McCann <mccann@jhu.edu>
4 * Copyright (C) 2012-2021 MATE Developers
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 * Authors: William Jon McCann <mccann@jhu.edu>
22 *
23 */
24
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <locale.h>
29 #include <glib.h>
30 #include <glib/gi18n.h>
31
32 #define DBUS_API_SUBJECT_TO_CHANGE
33 #include <dbus/dbus.h>
34 #include <dbus/dbus-glib.h>
35 #include <dbus/dbus-glib-lowlevel.h>
36
37 #define GS_SERVICE "org.mate.ScreenSaver"
38 #define GS_PATH "/org/mate/ScreenSaver"
39 #define GS_INTERFACE "org.mate.ScreenSaver"
40
41 static gboolean do_quit = FALSE;
42 static gboolean do_lock = FALSE;
43 static gboolean do_unlock = FALSE;
44 static gboolean do_cycle = FALSE;
45 static gboolean do_activate = FALSE;
46 static gboolean do_deactivate = FALSE;
47 static gboolean do_version = FALSE;
48 static gboolean do_poke = FALSE;
49 static gboolean do_inhibit = FALSE;
50
51 static gboolean do_query = FALSE;
52 static gboolean do_time = FALSE;
53
54 static char *inhibit_reason = NULL;
55 static char *inhibit_application = NULL;
56
57 static GOptionEntry entries [] =
58 {
59 {
60 "exit", 0, 0, G_OPTION_ARG_NONE, &do_quit,
61 N_("Causes the screensaver to exit gracefully"), NULL
62 },
63 {
64 "query", 'q', 0, G_OPTION_ARG_NONE, &do_query,
65 N_("Query the state of the screensaver"), NULL
66 },
67 {
68 "time", 't', 0, G_OPTION_ARG_NONE, &do_time,
69 N_("Query the length of time the screensaver has been active"), NULL
70 },
71 {
72 "lock", 'l', 0, G_OPTION_ARG_NONE, &do_lock,
73 N_("Tells the running screensaver process to lock the screen immediately"), NULL
74 },
75 {
76 "unlock", 'u', 0, G_OPTION_ARG_NONE, &do_unlock,
77 N_("Tells the running screensaver process to unlock the screen immediately"), NULL
78 },
79 {
80 "cycle", 'c', 0, G_OPTION_ARG_NONE, &do_cycle,
81 N_("If the screensaver is active then switch to another graphics demo"), NULL
82 },
83 {
84 "activate", 'a', 0, G_OPTION_ARG_NONE, &do_activate,
85 N_("Turn the screensaver on (blank the screen)"), NULL
86 },
87 {
88 "deactivate", 'd', 0, G_OPTION_ARG_NONE, &do_deactivate,
89 N_("If the screensaver is active then deactivate it (un-blank the screen)"), NULL
90 },
91 {
92 "poke", 'p', 0, G_OPTION_ARG_NONE, &do_poke,
93 N_("Poke the running screensaver to simulate user activity"), NULL
94 },
95 {
96 "inhibit", 'i', 0, G_OPTION_ARG_NONE, &do_inhibit,
97 N_("Inhibit the screensaver from activating. Command blocks while inhibit is active."), NULL
98 },
99 {
100 "application-name", 'n', 0, G_OPTION_ARG_STRING, &inhibit_application,
101 N_("The calling application that is inhibiting the screensaver"), NULL
102 },
103 {
104 "reason", 'r', 0, G_OPTION_ARG_STRING, &inhibit_reason,
105 N_("The reason for inhibiting the screensaver"), NULL
106 },
107 {
108 "version", 'V', 0, G_OPTION_ARG_NONE, &do_version,
109 N_("Version of this application"), NULL
110 },
111 { NULL }
112 };
113
114 static GMainLoop *loop = NULL;
115
116 static gboolean
screensaver_is_running(DBusConnection * connection)117 screensaver_is_running (DBusConnection *connection)
118 {
119 DBusError error;
120 gboolean exists;
121
122 g_return_val_if_fail (connection != NULL, FALSE);
123
124 dbus_error_init (&error);
125 exists = dbus_bus_name_has_owner (connection, GS_SERVICE, &error);
126 if (dbus_error_is_set (&error))
127 dbus_error_free (&error);
128
129 return exists;
130 }
131
132 static DBusMessage *
screensaver_send_message_inhibit(DBusConnection * connection,const char * application,const char * reason)133 screensaver_send_message_inhibit (DBusConnection *connection,
134 const char *application,
135 const char *reason)
136 {
137 DBusMessage *message;
138 DBusMessage *reply;
139 DBusError error;
140 DBusMessageIter iter;
141
142 g_return_val_if_fail (connection != NULL, NULL);
143
144 dbus_error_init (&error);
145
146 message = dbus_message_new_method_call (GS_SERVICE, GS_PATH, GS_INTERFACE, "Inhibit");
147 if (message == NULL)
148 {
149 g_warning ("Couldn't allocate the dbus message");
150 return NULL;
151 }
152
153 dbus_message_iter_init_append (message, &iter);
154 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &application);
155 dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &reason);
156
157 reply = dbus_connection_send_with_reply_and_block (connection,
158 message,
159 -1, &error);
160 if (dbus_error_is_set (&error))
161 {
162 g_warning ("%s raised:\n %s\n\n", error.name, error.message);
163 reply = NULL;
164 }
165
166 dbus_connection_flush (connection);
167
168 dbus_message_unref (message);
169 dbus_error_free (&error);
170
171 return reply;
172 }
173
174 static DBusMessage *
screensaver_send_message_bool(DBusConnection * connection,const char * name,gboolean value)175 screensaver_send_message_bool (DBusConnection *connection,
176 const char *name,
177 gboolean value)
178 {
179 DBusMessage *message;
180 DBusMessage *reply;
181 DBusError error;
182 DBusMessageIter iter;
183
184 g_return_val_if_fail (connection != NULL, NULL);
185 g_return_val_if_fail (name != NULL, NULL);
186
187 dbus_error_init (&error);
188
189 message = dbus_message_new_method_call (GS_SERVICE, GS_PATH, GS_INTERFACE, name);
190 if (message == NULL)
191 {
192 g_warning ("Couldn't allocate the dbus message");
193 return NULL;
194 }
195
196 dbus_message_iter_init_append (message, &iter);
197 dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &value);
198
199 reply = dbus_connection_send_with_reply_and_block (connection,
200 message,
201 -1, &error);
202 if (dbus_error_is_set (&error))
203 {
204 g_warning ("%s raised:\n %s\n\n", error.name, error.message);
205 reply = NULL;
206 }
207
208 dbus_connection_flush (connection);
209
210 dbus_message_unref (message);
211 dbus_error_free (&error);
212
213 return reply;
214 }
215
216 static DBusMessage *
screensaver_send_message_void(DBusConnection * connection,const char * name,gboolean expect_reply)217 screensaver_send_message_void (DBusConnection *connection,
218 const char *name,
219 gboolean expect_reply)
220 {
221 DBusMessage *message;
222 DBusMessage *reply;
223 DBusError error;
224
225 g_return_val_if_fail (connection != NULL, NULL);
226 g_return_val_if_fail (name != NULL, NULL);
227
228 dbus_error_init (&error);
229
230 message = dbus_message_new_method_call (GS_SERVICE, GS_PATH, GS_INTERFACE, name);
231 if (message == NULL)
232 {
233 g_warning ("Couldn't allocate the dbus message");
234 return NULL;
235 }
236
237 if (! expect_reply)
238 {
239 if (!dbus_connection_send (connection, message, NULL))
240 g_warning ("could not send message");
241 reply = NULL;
242 }
243 else
244 {
245 reply = dbus_connection_send_with_reply_and_block (connection,
246 message,
247 -1, &error);
248 if (dbus_error_is_set (&error))
249 {
250 g_warning ("%s raised:\n %s\n\n", error.name, error.message);
251 reply = NULL;
252 }
253 }
254 dbus_connection_flush (connection);
255
256 dbus_message_unref (message);
257 dbus_error_free (&error);
258
259 return reply;
260 }
261
262 static char **
get_string_from_iter(DBusMessageIter * iter,int * num_elements)263 get_string_from_iter (DBusMessageIter *iter,
264 int *num_elements)
265 {
266 int count;
267 char **buffer;
268
269 if (num_elements != NULL)
270 {
271 *num_elements = 0;
272 }
273
274 count = 0;
275 buffer = (char **)malloc (sizeof (char *) * 8);
276
277 if (buffer == NULL)
278 {
279 goto oom;
280 }
281
282 buffer[0] = NULL;
283 while (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRING)
284 {
285 const char *value;
286 char *str;
287
288 if ((count % 8) == 0 && count != 0)
289 {
290 buffer = realloc (buffer, sizeof (char *) * (count + 8));
291 if (buffer == NULL)
292 {
293 goto oom;
294 }
295 }
296
297 dbus_message_iter_get_basic (iter, &value);
298 str = strdup (value);
299 if (str == NULL)
300 {
301 goto oom;
302 }
303
304 buffer[count] = str;
305
306 dbus_message_iter_next (iter);
307 count++;
308 }
309
310 if ((count % 8) == 0)
311 {
312 buffer = realloc (buffer, sizeof (char *) * (count + 1));
313 if (buffer == NULL)
314 {
315 goto oom;
316 }
317 }
318
319 buffer[count] = NULL;
320 if (num_elements != NULL)
321 {
322 *num_elements = count;
323 }
324 return buffer;
325
326 oom:
327 g_debug ("%s %d : error allocating memory\n", __FILE__, __LINE__);
328 return NULL;
329
330 }
331
332 static gboolean
do_command(gpointer data)333 do_command (gpointer data)
334 {
335 DBusConnection *connection = data;
336 DBusMessage *reply;
337
338 if (do_quit)
339 {
340 reply = screensaver_send_message_void (connection, "Quit", FALSE);
341 goto done;
342 }
343
344 if (do_query)
345 {
346 DBusMessageIter iter;
347 DBusMessageIter array;
348 dbus_bool_t v;
349
350 reply = screensaver_send_message_void (connection, "GetActive", TRUE);
351 if (! reply)
352 {
353 g_message ("Did not receive a reply from the screensaver.");
354 goto done;
355 }
356
357 dbus_message_iter_init (reply, &iter);
358 dbus_message_iter_get_basic (&iter, &v);
359 g_print (_("The screensaver is %s\n"), v ? _("active") : _("inactive"));
360
361 dbus_message_unref (reply);
362
363 reply = screensaver_send_message_void (connection, "GetInhibitors", TRUE);
364 if (! reply)
365 {
366 g_message ("Did not receive a reply from screensaver.");
367 goto done;
368 }
369
370 dbus_message_iter_init (reply, &iter);
371 dbus_message_iter_recurse (&iter, &array);
372
373 if (dbus_message_iter_get_arg_type (&array) == DBUS_TYPE_INVALID)
374 {
375 g_print (_("The screensaver is not inhibited\n"));
376 }
377 else
378 {
379 char **inhibitors;
380 int i;
381 int num;
382
383 g_print (_("The screensaver is being inhibited by:\n"));
384 inhibitors = get_string_from_iter (&array, &num);
385 for (i = 0; i < num; i++)
386 {
387 g_print ("\t%s\n", inhibitors[i]);
388 }
389 g_strfreev (inhibitors);
390 }
391
392 dbus_message_unref (reply);
393 }
394
395 if (do_time)
396 {
397 DBusMessageIter iter;
398 dbus_bool_t v;
399 dbus_int32_t t;
400
401 reply = screensaver_send_message_void (connection, "GetActive", TRUE);
402 if (! reply)
403 {
404 g_message ("Did not receive a reply from the screensaver.");
405 goto done;
406 }
407
408 dbus_message_iter_init (reply, &iter);
409 dbus_message_iter_get_basic (&iter, &v);
410 dbus_message_unref (reply);
411
412 if (v)
413 {
414
415 reply = screensaver_send_message_void (connection, "GetActiveTime", TRUE);
416 dbus_message_iter_init (reply, &iter);
417 dbus_message_iter_get_basic (&iter, &t);
418 g_print (_("The screensaver has been active for %d seconds.\n"), t);
419
420 dbus_message_unref (reply);
421 }
422 else
423 {
424 g_print (_("The screensaver is not currently active.\n"));
425 }
426 }
427
428 if (do_lock)
429 {
430 reply = screensaver_send_message_void (connection, "Lock", FALSE);
431 }
432
433 if (do_unlock)
434 {
435 reply = screensaver_send_message_void (connection, "Unlock", FALSE);
436 }
437
438 if (do_cycle)
439 {
440 reply = screensaver_send_message_void (connection, "Cycle", FALSE);
441 }
442
443 if (do_poke)
444 {
445 reply = screensaver_send_message_void (connection, "SimulateUserActivity", FALSE);
446 }
447
448 if (do_activate)
449 {
450 reply = screensaver_send_message_bool (connection, "SetActive", TRUE);
451 if (! reply)
452 {
453 g_message ("Did not receive a reply from the screensaver.");
454 goto done;
455 }
456 dbus_message_unref (reply);
457 }
458
459 if (do_deactivate)
460 {
461 reply = screensaver_send_message_bool (connection, "SetActive", FALSE);
462 if (! reply)
463 {
464 g_message ("Did not receive a reply from the screensaver.");
465 goto done;
466 }
467 dbus_message_unref (reply);
468 }
469
470 if (do_inhibit)
471 {
472 reply = screensaver_send_message_inhibit (connection,
473 inhibit_application ? inhibit_application : "Unknown",
474 inhibit_reason ? inhibit_reason : "Unknown");
475 if (! reply)
476 {
477 g_message ("Did not receive a reply from the screensaver.");
478 goto done;
479 }
480 dbus_message_unref (reply);
481
482 return FALSE;
483 }
484
485 done:
486 g_main_loop_quit (loop);
487
488 return FALSE;
489 }
490
491 int
main(int argc,char ** argv)492 main (int argc,
493 char **argv)
494 {
495 DBusConnection *connection;
496 DBusError dbus_error;
497 GOptionContext *context;
498 gboolean retval;
499 GError *error = NULL;
500
501 #ifdef ENABLE_NLS
502 bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
503 # ifdef HAVE_BIND_TEXTDOMAIN_CODESET
504 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
505 # endif
506 textdomain (GETTEXT_PACKAGE);
507 #endif
508
509 g_set_prgname (argv[0]);
510
511 if (setlocale (LC_ALL, "") == NULL)
512 g_warning ("Locale not understood by C library, internationalization will not work\n");
513
514 context = g_option_context_new (NULL);
515 g_option_context_add_main_entries (context, entries, NULL);
516 retval = g_option_context_parse (context, &argc, &argv, &error);
517
518 g_option_context_free (context);
519
520 if (! retval)
521 {
522 g_warning ("%s", error->message);
523 g_error_free (error);
524 exit (1);
525 }
526
527 if (do_version)
528 {
529 g_print ("%s %s\n", argv [0], VERSION);
530 exit (1);
531 }
532
533 dbus_error_init (&dbus_error);
534 connection = dbus_bus_get (DBUS_BUS_SESSION, &dbus_error);
535 if (! connection)
536 {
537 g_message ("Failed to connect to the D-BUS daemon: %s", dbus_error.message);
538 dbus_error_free (&dbus_error);
539 exit (1);
540 }
541
542 dbus_connection_setup_with_g_main (connection, NULL);
543
544 if (! screensaver_is_running (connection))
545 {
546 g_message ("Screensaver is not running!");
547 exit (1);
548 }
549
550 g_idle_add (do_command, connection);
551
552 loop = g_main_loop_new (NULL, FALSE);
553 g_main_loop_run (loop);
554
555 return 0;
556 }
557