blob: c5584ff0d7bbe49315e4462091865e77682e7577 [file] [log] [blame]
David Sodmanbbcb0522014-09-19 10:34:07 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <stdlib.h>
David Sodman8ef20062015-01-06 09:23:40 -08008
Stéphane Marchesin62561a12015-12-11 17:32:37 -08009#include "dbus.h"
David Sodman8ef20062015-01-06 09:23:40 -080010#include "dbus_interface.h"
11#include "image.h"
12#include "input.h"
13#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070014#include "util.h"
15
David Sodman8ef20062015-01-06 09:23:40 -080016#define COMMAND_MAKE_VT "MakeVT"
17#define COMMAND_SWITCH_VT "SwitchVT"
18#define COMMAND_TERMINATE "Terminate"
19#define COMMAND_IMAGE "Image"
20
21#define DBUS_DEFAULT_DELAY 3000
22
Dominik Behr797a3832016-01-11 15:53:11 -080023typedef struct _dbus_t dbus_t;
24
David Sodmanbbcb0522014-09-19 10:34:07 -070025struct _dbus_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080026 DBusConnection* conn;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080027 DBusWatch* watch;
David Sodman8ef20062015-01-06 09:23:40 -080028 int fd;
David Sodmanbbcb0522014-09-19 10:34:07 -070029};
30
Dominik Behr797a3832016-01-11 15:53:11 -080031static dbus_t *dbus = NULL;
32
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080033static DBusHandlerResult handle_switchvt(DBusConnection* connection,
34 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -080035{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080036 DBusMessage* reply;
37 DBusMessage* msg;
David Sodman8ef20062015-01-06 09:23:40 -080038 DBusError error;
39 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080040 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -080041 unsigned int vt;
42
43 dbus_error_init(&error);
44 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
45 &vt, DBUS_TYPE_INVALID);
46
47 if (!stat) {
48 LOG(ERROR, "SwitchVT method error, no VT argument");
49 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
50 }
51
Stéphane Marchesin92a297d2016-01-07 20:24:55 -080052 if (vt > term_get_max_terminals()) {
David Sodman8ef20062015-01-06 09:23:40 -080053 LOG(ERROR, "SwtichVT: invalid terminal");
54 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
55 }
56
57 if (vt == 0) {
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -080058 terminal = term_create_term(vt);
David Sodman8ef20062015-01-06 09:23:40 -080059 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -070060 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080061 msg = dbus_message_new_method_call(
62 kLibCrosServiceName,
63 kLibCrosServicePath,
64 kLibCrosServiceInterface,
65 kTakeDisplayOwnership);
66 dbus_connection_send_with_reply_and_block(connection, msg,
67 DBUS_DEFAULT_DELAY, NULL);
68 }
69 reply = dbus_message_new_method_return(message);
70 dbus_connection_send(connection, reply, NULL);
71 return DBUS_HANDLER_RESULT_HANDLED;
72 } else {
73 /*
74 * If we are switching to a new term, and if a
75 * given term is active, then de-activate the
76 * current terminal
77 */
Stéphane Marchesine38b8e72016-01-07 19:20:28 -080078 terminal = input_get_current_term();
David Sodman8ef20062015-01-06 09:23:40 -080079 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -070080 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080081
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -080082 terminal = term_create_term(vt);
David Sodman8ef20062015-01-06 09:23:40 -080083 if (term_is_valid(terminal)) {
84 msg = dbus_message_new_method_call(
85 kLibCrosServiceName,
86 kLibCrosServicePath,
87 kLibCrosServiceInterface,
88 kReleaseDisplayOwnership);
89 dbus_connection_send_with_reply_and_block(connection, msg,
90 DBUS_DEFAULT_DELAY, NULL);
91 term_activate(terminal);
92
93 reply = dbus_message_new_method_return(message);
94 dbus_connection_send(connection, reply, NULL);
95 return DBUS_HANDLER_RESULT_HANDLED;
96 }
97 }
98
99 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
100}
101
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800102static DBusHandlerResult handle_makevt(DBusConnection* connection,
103 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800104{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800105 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800106 DBusError error;
107 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800108 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -0800109 unsigned int vt;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800110 const char* reply_str;
David Sodman8ef20062015-01-06 09:23:40 -0800111
112 dbus_error_init(&error);
113 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
114 &vt, DBUS_TYPE_INVALID);
115
116 if (!stat) {
117 LOG(ERROR, "SwitchVT method error, not VT argument");
118 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
119 }
120
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800121 if ((vt < 1) || (vt > term_get_max_terminals())) {
David Sodman8ef20062015-01-06 09:23:40 -0800122 LOG(ERROR, "SwtichVT: invalid terminal");
123 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
124 }
125
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -0800126 terminal = term_create_term(vt);
David Sodman8ef20062015-01-06 09:23:40 -0800127 reply_str = term_get_ptsname(terminal);
128
129 reply = dbus_message_new_method_return(message);
130 dbus_message_append_args(reply,
131 DBUS_TYPE_STRING, &reply_str,
132 DBUS_TYPE_INVALID);
133 dbus_connection_send(connection, reply, NULL);
134
135 return DBUS_HANDLER_RESULT_HANDLED;
136}
137
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800138static DBusHandlerResult handle_terminate(DBusConnection* connection,
139 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800140{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800141 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800142
143 reply = dbus_message_new_method_return(message);
144 dbus_connection_send(connection, reply, NULL);
145 exit(EXIT_SUCCESS);
146}
147
David Sodman8ef20062015-01-06 09:23:40 -0800148#define NUM_IMAGE_PARAMETERS (2)
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800149static DBusHandlerResult handle_image(DBusConnection* connection,
150 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800151{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800152 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800153 DBusError error;
154 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800155 terminal_t* terminal;
156 image_t* image;
David Sodman8ef20062015-01-06 09:23:40 -0800157 int i;
158 int x, y;
159 char* option[NUM_IMAGE_PARAMETERS];
160 char* optname;
161 char* optval;
162 int status;
163
164 dbus_error_init(&error);
165 stat = dbus_message_get_args(message, &error,
166 DBUS_TYPE_STRING, &option[0],
167 DBUS_TYPE_STRING, &option[1],
168 DBUS_TYPE_INVALID);
169
170 image = image_create();
171 if (image == NULL) {
172 LOG(WARNING, "failed to create image");
173 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
174 }
175
176 if (stat) {
177 for (i = 0; i < NUM_IMAGE_PARAMETERS; i++) {
178 optname = NULL;
179 optval = NULL;
180 parse_image_option(option[i], &optname, &optval);
181 if (strncmp(optname, "image", strlen("image")) == 0) {
182 image_set_filename(image, optval);
183 } else if (strncmp(optname, "location", strlen("location")) == 0) {
184 parse_location(optval, &x, &y);
185 image_set_location(image, x, y);
186 } else if (strncmp(optname, "offset", strlen("offset")) == 0) {
187 parse_location(optval, &x, &y);
188 image_set_offset(image, x, y);
189 }
190 if (optname)
191 free(optname);
192 if (optval)
193 free(optval);
194 }
195 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700196 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800197 }
198
199 status = image_load_image_from_file(image);
200 if (status != 0) {
201 LOG(WARNING, "image_load_image_from_file failed: %d", status);
David Sodmanf0a925a2015-05-04 11:19:19 -0700202 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800203 }
204
Stéphane Marchesine38b8e72016-01-07 19:20:28 -0800205 terminal = input_get_current_term();
David Sodman8ef20062015-01-06 09:23:40 -0800206 if (!terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700207 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800208
David Sodmanf0a925a2015-05-04 11:19:19 -0700209 status = term_show_image(terminal, image);
210 if (status != 0) {
211 LOG(WARNING, "term_show_image failed: %d", status);
212 goto fail;
213 }
David Sodman8ef20062015-01-06 09:23:40 -0800214 image_release(image);
215
216 reply = dbus_message_new_method_return(message);
217 dbus_connection_send(connection, reply, NULL);
218
219 return DBUS_HANDLER_RESULT_HANDLED;
David Sodmanf0a925a2015-05-04 11:19:19 -0700220fail:
221 if (image)
222 image_release(image);
223 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800224}
225
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800226static void frecon_dbus_unregister(DBusConnection* connection, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800227{
228}
229
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800230static DBusHandlerResult frecon_dbus_message_handler(DBusConnection* connection,
231 DBusMessage* message,
232 void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800233{
234 if (dbus_message_is_method_call(message,
235 kFreconDbusInterface, COMMAND_SWITCH_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800236 return handle_switchvt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800237 } else if (dbus_message_is_method_call(message,
238 kFreconDbusInterface, COMMAND_MAKE_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800239 return handle_makevt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800240 }
241 else if (dbus_message_is_method_call(message,
242 kFreconDbusInterface, COMMAND_TERMINATE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800243 return handle_terminate(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800244 } else if (dbus_message_is_method_call(message,
245 kFreconDbusInterface, COMMAND_IMAGE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800246 return handle_image(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800247 }
248
249 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800250}
251
252static DBusObjectPathVTable
253frecon_vtable = {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800254 frecon_dbus_unregister,
255 frecon_dbus_message_handler,
David Sodman8ef20062015-01-06 09:23:40 -0800256 NULL
257};
258
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800259static dbus_bool_t add_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800260{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800261 dbus_t* dbus = (dbus_t*)data;
David Sodman8ef20062015-01-06 09:23:40 -0800262 dbus->watch = w;
263
264 return TRUE;
265}
266
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800267static void remove_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800268{
269}
270
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800271static void toggle_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800272{
273}
274
Dominik Behr797a3832016-01-11 15:53:11 -0800275bool dbus_is_initialized(void)
276{
277 return !!dbus;
278}
279
280bool dbus_init()
David Sodmanbbcb0522014-09-19 10:34:07 -0700281{
282 dbus_t* new_dbus;
283 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800284 int result;
285 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700286
287 dbus_error_init(&err);
288
289 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800290
291 if (!new_dbus)
Dominik Behr797a3832016-01-11 15:53:11 -0800292 return false;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800293
David Sodman8ef20062015-01-06 09:23:40 -0800294 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700295
296 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
297 if (dbus_error_is_set(&err)) {
298 LOG(ERROR, "Cannot get dbus connection");
299 free(new_dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800300 return false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700301 }
302
David Sodman8ef20062015-01-06 09:23:40 -0800303 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
304 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
305
306 if (result <= 0) {
307 LOG(ERROR, "Unable to get name for server");
308 }
309
310 stat = dbus_connection_register_object_path(new_dbus->conn,
311 kFreconDbusPath,
312 &frecon_vtable,
313 NULL);
314
315 if (!stat) {
316 LOG(ERROR, "failed to register object path");
317 }
318
319 stat = dbus_connection_set_watch_functions(new_dbus->conn,
320 add_watch, remove_watch, toggle_watch,
321 new_dbus, NULL);
322
323 if (!stat) {
324 LOG(ERROR, "Failed to set watch functions");
325 }
326
David Sodmanbbcb0522014-09-19 10:34:07 -0700327 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
328
Dominik Behr797a3832016-01-11 15:53:11 -0800329 dbus = new_dbus;
330 return true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700331}
332
Dominik Behr797a3832016-01-11 15:53:11 -0800333static bool dbus_method_call0(const char* service_name,
334 const char* service_path,
335 const char* service_interface,
336 const char* method)
David Sodman003faed2014-11-03 09:02:10 -0800337{
Dominik Behr797a3832016-01-11 15:53:11 -0800338 DBusMessage* msg = NULL;
339 if (!dbus) {
340 LOG(ERROR, "dbus not initialized");
341 return false;
342 }
David Sodman003faed2014-11-03 09:02:10 -0800343
344 msg = dbus_message_new_method_call(service_name,
345 service_path, service_interface, method);
346
347 if (!msg)
348 return false;
349
350 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800351 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800352 dbus_message_unref(msg);
353 return false;
354 }
355
356 dbus_connection_flush(dbus->conn);
357 dbus_message_unref(msg);
358
359 return true;
360}
361
Dominik Behr797a3832016-01-11 15:53:11 -0800362static bool dbus_method_call1(const char* service_name,
363 const char* service_path,
364 const char* service_interface,
365 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700366{
Dominik Behr797a3832016-01-11 15:53:11 -0800367 DBusMessage* msg = NULL;
368 if (!dbus) {
369 LOG(ERROR, "dbus not initialized");
370 return false;
371 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700372
373 msg = dbus_message_new_method_call(service_name,
374 service_path, service_interface, method);
375
376 if (!msg)
377 return false;
378
379 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700380 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700381 dbus_message_unref(msg);
382 return false;
383 }
384
385 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800386 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700387 dbus_message_unref(msg);
388 return false;
389 }
390
391 dbus_connection_flush(dbus->conn);
392 dbus_message_unref(msg);
393
394 return true;
395}
396
Dominik Behr797a3832016-01-11 15:53:11 -0800397void dbus_destroy(void)
David Sodmanbbcb0522014-09-19 10:34:07 -0700398{
399 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800400 * dbus_bus_get() is, unref documentation is rather
401 * unclear. Not a big issue but it would be nice to
402 * clean up properly here
403 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700404 /* dbus_connection_unref(dbus->conn); */
Dominik Behr797a3832016-01-11 15:53:11 -0800405 if (dbus) {
David Sodman8ef20062015-01-06 09:23:40 -0800406 free(dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800407 dbus = NULL;
408 }
David Sodman8ef20062015-01-06 09:23:40 -0800409}
410
Dominik Behr797a3832016-01-11 15:53:11 -0800411int dbus_add_fds(fd_set* read_set, fd_set* exception_set)
David Sodman8ef20062015-01-06 09:23:40 -0800412{
Dominik Behr797a3832016-01-11 15:53:11 -0800413 if (!dbus)
414 return -1;
415
David Sodman8ef20062015-01-06 09:23:40 -0800416 if (dbus->fd < 0)
417 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
418
419 if (dbus->fd >= 0) {
420 FD_SET(dbus->fd, read_set);
421 FD_SET(dbus->fd, exception_set);
422 }
David Sodman8ef20062015-01-06 09:23:40 -0800423
424 return dbus->fd;
425}
426
Dominik Behr797a3832016-01-11 15:53:11 -0800427void dbus_dispatch_io(void)
David Sodman8ef20062015-01-06 09:23:40 -0800428{
Dominik Behr797a3832016-01-11 15:53:11 -0800429 if (!dbus)
430 return;
431
David Sodman8ef20062015-01-06 09:23:40 -0800432 dbus_watch_handle(dbus->watch, DBUS_WATCH_READABLE);
433 while (dbus_connection_get_dispatch_status(dbus->conn)
434 == DBUS_DISPATCH_DATA_REMAINS) {
435 dbus_connection_dispatch(dbus->conn);
436 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700437}
Dominik Behr797a3832016-01-11 15:53:11 -0800438
439void dbus_report_user_activity(int activity_type)
440{
441 dbus_bool_t allow_off = false;
442 if (!dbus)
443 return;
444
445 dbus_method_call1(kPowerManagerServiceName,
446 kPowerManagerServicePath,
447 kPowerManagerInterface,
448 kHandleUserActivityMethod,
449 DBUS_TYPE_INT32, &activity_type);
450
451 switch (activity_type) {
452 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
453 (void)dbus_method_call0(kPowerManagerServiceName,
454 kPowerManagerServicePath,
455 kPowerManagerInterface,
456 kIncreaseScreenBrightnessMethod);
457 break;
458 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
459 /*
460 * Shouldn't allow the screen to go
461 * completely off while frecon is active
462 * so passing false to allow_off
463 */
464 (void)dbus_method_call1(kPowerManagerServiceName,
465 kPowerManagerServicePath,
466 kPowerManagerInterface,
467 kDecreaseScreenBrightnessMethod,
468 DBUS_TYPE_BOOLEAN, &allow_off);
469 break;
470 }
471}
472
473void dbus_take_display_ownership(void)
474{
475 if (!dbus)
476 return;
477 (void)dbus_method_call0(kLibCrosServiceName,
478 kLibCrosServicePath,
479 kLibCrosServiceInterface,
480 kTakeDisplayOwnership);
481}
482
483void dbus_release_display_ownership(void)
484{
485 if (!dbus)
486 return;
487 (void)dbus_method_call0(kLibCrosServiceName,
488 kLibCrosServicePath,
489 kLibCrosServiceInterface,
490 kReleaseDisplayOwnership);
491}
492