blob: 6a78b2e0c62b8aef4ac550260bb941f024d1c60d [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"
David Sodman8ef20062015-01-06 09:23:40 -080012#include "term.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070013#include "util.h"
14
David Sodman8ef20062015-01-06 09:23:40 -080015#define COMMAND_MAKE_VT "MakeVT"
16#define COMMAND_SWITCH_VT "SwitchVT"
17#define COMMAND_TERMINATE "Terminate"
18#define COMMAND_IMAGE "Image"
19
20#define DBUS_DEFAULT_DELAY 3000
21
Dominik Behr797a3832016-01-11 15:53:11 -080022typedef struct _dbus_t dbus_t;
23
David Sodmanbbcb0522014-09-19 10:34:07 -070024struct _dbus_t {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080025 DBusConnection* conn;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080026 DBusWatch* watch;
David Sodman8ef20062015-01-06 09:23:40 -080027 int fd;
David Sodmanbbcb0522014-09-19 10:34:07 -070028};
29
Dominik Behr797a3832016-01-11 15:53:11 -080030static dbus_t *dbus = NULL;
31
Stéphane Marchesin8fc13522015-12-14 17:02:28 -080032static DBusHandlerResult handle_switchvt(DBusConnection* connection,
33 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -080034{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080035 DBusMessage* reply;
36 DBusMessage* msg;
David Sodman8ef20062015-01-06 09:23:40 -080037 DBusError error;
38 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080039 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -080040 unsigned int vt;
41
42 dbus_error_init(&error);
43 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
44 &vt, DBUS_TYPE_INVALID);
45
46 if (!stat) {
47 LOG(ERROR, "SwitchVT method error, no VT argument");
48 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
49 }
50
Stéphane Marchesin92a297d2016-01-07 20:24:55 -080051 if (vt > term_get_max_terminals()) {
David Sodman8ef20062015-01-06 09:23:40 -080052 LOG(ERROR, "SwtichVT: invalid terminal");
53 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
54 }
55
56 if (vt == 0) {
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -080057 terminal = term_create_term(vt);
David Sodman8ef20062015-01-06 09:23:40 -080058 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -070059 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080060 msg = dbus_message_new_method_call(
61 kLibCrosServiceName,
62 kLibCrosServicePath,
63 kLibCrosServiceInterface,
64 kTakeDisplayOwnership);
65 dbus_connection_send_with_reply_and_block(connection, msg,
66 DBUS_DEFAULT_DELAY, NULL);
67 }
68 reply = dbus_message_new_method_return(message);
69 dbus_connection_send(connection, reply, NULL);
70 return DBUS_HANDLER_RESULT_HANDLED;
71 } else {
72 /*
73 * If we are switching to a new term, and if a
74 * given term is active, then de-activate the
75 * current terminal
76 */
Dominik Behr4defb362016-01-13 12:36:14 -080077 terminal = term_get_current_terminal();
David Sodman8ef20062015-01-06 09:23:40 -080078 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -070079 term_deactivate(terminal);
David Sodman8ef20062015-01-06 09:23:40 -080080
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -080081 terminal = term_create_term(vt);
David Sodman8ef20062015-01-06 09:23:40 -080082 if (term_is_valid(terminal)) {
83 msg = dbus_message_new_method_call(
84 kLibCrosServiceName,
85 kLibCrosServicePath,
86 kLibCrosServiceInterface,
87 kReleaseDisplayOwnership);
88 dbus_connection_send_with_reply_and_block(connection, msg,
89 DBUS_DEFAULT_DELAY, NULL);
90 term_activate(terminal);
91
92 reply = dbus_message_new_method_return(message);
93 dbus_connection_send(connection, reply, NULL);
94 return DBUS_HANDLER_RESULT_HANDLED;
95 }
96 }
97
98 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
99}
100
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800101static DBusHandlerResult handle_makevt(DBusConnection* connection,
102 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800103{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800104 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800105 DBusError error;
106 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800107 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -0800108 unsigned int vt;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800109 const char* reply_str;
David Sodman8ef20062015-01-06 09:23:40 -0800110
111 dbus_error_init(&error);
112 stat = dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
113 &vt, DBUS_TYPE_INVALID);
114
115 if (!stat) {
116 LOG(ERROR, "SwitchVT method error, not VT argument");
117 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
118 }
119
Stéphane Marchesin92a297d2016-01-07 20:24:55 -0800120 if ((vt < 1) || (vt > term_get_max_terminals())) {
David Sodman8ef20062015-01-06 09:23:40 -0800121 LOG(ERROR, "SwtichVT: invalid terminal");
122 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
123 }
124
Stéphane Marchesin0a7ce422016-01-07 20:45:47 -0800125 terminal = term_create_term(vt);
David Sodman8ef20062015-01-06 09:23:40 -0800126 reply_str = term_get_ptsname(terminal);
127
128 reply = dbus_message_new_method_return(message);
129 dbus_message_append_args(reply,
130 DBUS_TYPE_STRING, &reply_str,
131 DBUS_TYPE_INVALID);
132 dbus_connection_send(connection, reply, NULL);
133
134 return DBUS_HANDLER_RESULT_HANDLED;
135}
136
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800137static DBusHandlerResult handle_terminate(DBusConnection* connection,
138 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800139{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800140 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800141
142 reply = dbus_message_new_method_return(message);
143 dbus_connection_send(connection, reply, NULL);
144 exit(EXIT_SUCCESS);
145}
146
David Sodman8ef20062015-01-06 09:23:40 -0800147#define NUM_IMAGE_PARAMETERS (2)
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800148static DBusHandlerResult handle_image(DBusConnection* connection,
149 DBusMessage* message)
David Sodman8ef20062015-01-06 09:23:40 -0800150{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800151 DBusMessage* reply;
David Sodman8ef20062015-01-06 09:23:40 -0800152 DBusError error;
153 dbus_bool_t stat;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800154 terminal_t* terminal;
155 image_t* image;
David Sodman8ef20062015-01-06 09:23:40 -0800156 int i;
157 int x, y;
158 char* option[NUM_IMAGE_PARAMETERS];
159 char* optname;
160 char* optval;
161 int status;
162
163 dbus_error_init(&error);
164 stat = dbus_message_get_args(message, &error,
165 DBUS_TYPE_STRING, &option[0],
166 DBUS_TYPE_STRING, &option[1],
167 DBUS_TYPE_INVALID);
168
169 image = image_create();
170 if (image == NULL) {
171 LOG(WARNING, "failed to create image");
172 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
173 }
174
175 if (stat) {
176 for (i = 0; i < NUM_IMAGE_PARAMETERS; i++) {
177 optname = NULL;
178 optval = NULL;
179 parse_image_option(option[i], &optname, &optval);
180 if (strncmp(optname, "image", strlen("image")) == 0) {
181 image_set_filename(image, optval);
182 } else if (strncmp(optname, "location", strlen("location")) == 0) {
183 parse_location(optval, &x, &y);
184 image_set_location(image, x, y);
185 } else if (strncmp(optname, "offset", strlen("offset")) == 0) {
186 parse_location(optval, &x, &y);
187 image_set_offset(image, x, y);
188 }
189 if (optname)
190 free(optname);
191 if (optval)
192 free(optval);
193 }
194 } else {
David Sodmanf0a925a2015-05-04 11:19:19 -0700195 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800196 }
197
198 status = image_load_image_from_file(image);
199 if (status != 0) {
200 LOG(WARNING, "image_load_image_from_file failed: %d", status);
David Sodmanf0a925a2015-05-04 11:19:19 -0700201 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800202 }
203
Dominik Behr4defb362016-01-13 12:36:14 -0800204 terminal = term_get_current_terminal();
David Sodman8ef20062015-01-06 09:23:40 -0800205 if (!terminal)
David Sodmanf0a925a2015-05-04 11:19:19 -0700206 goto fail;
David Sodman8ef20062015-01-06 09:23:40 -0800207
David Sodmanf0a925a2015-05-04 11:19:19 -0700208 status = term_show_image(terminal, image);
209 if (status != 0) {
210 LOG(WARNING, "term_show_image failed: %d", status);
211 goto fail;
212 }
David Sodman8ef20062015-01-06 09:23:40 -0800213 image_release(image);
214
215 reply = dbus_message_new_method_return(message);
216 dbus_connection_send(connection, reply, NULL);
217
218 return DBUS_HANDLER_RESULT_HANDLED;
David Sodmanf0a925a2015-05-04 11:19:19 -0700219fail:
220 if (image)
221 image_release(image);
222 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800223}
224
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800225static void frecon_dbus_unregister(DBusConnection* connection, void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800226{
227}
228
Stéphane Marchesin8fc13522015-12-14 17:02:28 -0800229static DBusHandlerResult frecon_dbus_message_handler(DBusConnection* connection,
230 DBusMessage* message,
231 void* user_data)
David Sodman8ef20062015-01-06 09:23:40 -0800232{
233 if (dbus_message_is_method_call(message,
234 kFreconDbusInterface, COMMAND_SWITCH_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800235 return handle_switchvt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800236 } else if (dbus_message_is_method_call(message,
237 kFreconDbusInterface, COMMAND_MAKE_VT)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800238 return handle_makevt(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800239 }
240 else if (dbus_message_is_method_call(message,
241 kFreconDbusInterface, COMMAND_TERMINATE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800242 return handle_terminate(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800243 } else if (dbus_message_is_method_call(message,
244 kFreconDbusInterface, COMMAND_IMAGE)) {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800245 return handle_image(connection, message);
David Sodman8ef20062015-01-06 09:23:40 -0800246 }
247
248 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
David Sodman8ef20062015-01-06 09:23:40 -0800249}
250
251static DBusObjectPathVTable
252frecon_vtable = {
Stéphane Marchesinaf9e9ff2015-12-11 17:49:12 -0800253 frecon_dbus_unregister,
254 frecon_dbus_message_handler,
David Sodman8ef20062015-01-06 09:23:40 -0800255 NULL
256};
257
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800258static dbus_bool_t add_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800259{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800260 dbus_t* dbus = (dbus_t*)data;
David Sodman8ef20062015-01-06 09:23:40 -0800261 dbus->watch = w;
262
263 return TRUE;
264}
265
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800266static void remove_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800267{
268}
269
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800270static void toggle_watch(DBusWatch* w, void* data)
David Sodman8ef20062015-01-06 09:23:40 -0800271{
272}
273
Dominik Behr797a3832016-01-11 15:53:11 -0800274bool dbus_is_initialized(void)
275{
276 return !!dbus;
277}
278
279bool dbus_init()
David Sodmanbbcb0522014-09-19 10:34:07 -0700280{
281 dbus_t* new_dbus;
282 DBusError err;
David Sodman8ef20062015-01-06 09:23:40 -0800283 int result;
284 dbus_bool_t stat;
David Sodmanbbcb0522014-09-19 10:34:07 -0700285
286 dbus_error_init(&err);
287
288 new_dbus = (dbus_t*)calloc(1, sizeof(*new_dbus));
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800289
290 if (!new_dbus)
Dominik Behr797a3832016-01-11 15:53:11 -0800291 return false;
Stéphane Marchesinc236e0b2015-12-14 15:29:15 -0800292
David Sodman8ef20062015-01-06 09:23:40 -0800293 new_dbus->fd = -1;
David Sodmanbbcb0522014-09-19 10:34:07 -0700294
295 new_dbus->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
296 if (dbus_error_is_set(&err)) {
297 LOG(ERROR, "Cannot get dbus connection");
298 free(new_dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800299 return false;
David Sodmanbbcb0522014-09-19 10:34:07 -0700300 }
301
David Sodman8ef20062015-01-06 09:23:40 -0800302 result = dbus_bus_request_name(new_dbus->conn, kFreconDbusInterface,
303 DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
304
305 if (result <= 0) {
306 LOG(ERROR, "Unable to get name for server");
307 }
308
309 stat = dbus_connection_register_object_path(new_dbus->conn,
310 kFreconDbusPath,
311 &frecon_vtable,
312 NULL);
313
314 if (!stat) {
315 LOG(ERROR, "failed to register object path");
316 }
317
318 stat = dbus_connection_set_watch_functions(new_dbus->conn,
319 add_watch, remove_watch, toggle_watch,
320 new_dbus, NULL);
321
322 if (!stat) {
323 LOG(ERROR, "Failed to set watch functions");
324 }
325
David Sodmanbbcb0522014-09-19 10:34:07 -0700326 dbus_connection_set_exit_on_disconnect(new_dbus->conn, FALSE);
327
Dominik Behr797a3832016-01-11 15:53:11 -0800328 dbus = new_dbus;
329 return true;
David Sodmanbbcb0522014-09-19 10:34:07 -0700330}
331
Dominik Behr797a3832016-01-11 15:53:11 -0800332static bool dbus_method_call0(const char* service_name,
333 const char* service_path,
334 const char* service_interface,
335 const char* method)
David Sodman003faed2014-11-03 09:02:10 -0800336{
Dominik Behr797a3832016-01-11 15:53:11 -0800337 DBusMessage* msg = NULL;
338 if (!dbus) {
339 LOG(ERROR, "dbus not initialized");
340 return false;
341 }
David Sodman003faed2014-11-03 09:02:10 -0800342
343 msg = dbus_message_new_method_call(service_name,
344 service_path, service_interface, method);
345
346 if (!msg)
347 return false;
348
349 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800350 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodman003faed2014-11-03 09:02:10 -0800351 dbus_message_unref(msg);
352 return false;
353 }
354
355 dbus_connection_flush(dbus->conn);
356 dbus_message_unref(msg);
357
358 return true;
359}
360
Dominik Behr797a3832016-01-11 15:53:11 -0800361static bool dbus_method_call1(const char* service_name,
362 const char* service_path,
363 const char* service_interface,
364 const char* method, int arg_type, void* param)
David Sodmanbbcb0522014-09-19 10:34:07 -0700365{
Dominik Behr797a3832016-01-11 15:53:11 -0800366 DBusMessage* msg = NULL;
367 if (!dbus) {
368 LOG(ERROR, "dbus not initialized");
369 return false;
370 }
David Sodmanbbcb0522014-09-19 10:34:07 -0700371
372 msg = dbus_message_new_method_call(service_name,
373 service_path, service_interface, method);
374
375 if (!msg)
376 return false;
377
378 if (!dbus_message_append_args(msg,
David Sodman19e4f9d2015-03-10 11:11:09 -0700379 arg_type, param, DBUS_TYPE_INVALID)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700380 dbus_message_unref(msg);
381 return false;
382 }
383
384 if (!dbus_connection_send_with_reply_and_block(dbus->conn,
David Sodman8ef20062015-01-06 09:23:40 -0800385 msg, DBUS_DEFAULT_DELAY, NULL)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700386 dbus_message_unref(msg);
387 return false;
388 }
389
390 dbus_connection_flush(dbus->conn);
391 dbus_message_unref(msg);
392
393 return true;
394}
395
Dominik Behr797a3832016-01-11 15:53:11 -0800396void dbus_destroy(void)
David Sodmanbbcb0522014-09-19 10:34:07 -0700397{
398 /* FIXME - not sure what the right counterpart to
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800399 * dbus_bus_get() is, unref documentation is rather
400 * unclear. Not a big issue but it would be nice to
401 * clean up properly here
402 */
David Sodmanbbcb0522014-09-19 10:34:07 -0700403 /* dbus_connection_unref(dbus->conn); */
Dominik Behr797a3832016-01-11 15:53:11 -0800404 if (dbus) {
David Sodman8ef20062015-01-06 09:23:40 -0800405 free(dbus);
Dominik Behr797a3832016-01-11 15:53:11 -0800406 dbus = NULL;
407 }
David Sodman8ef20062015-01-06 09:23:40 -0800408}
409
Dominik Behrd7112672016-01-20 16:59:34 -0800410void dbus_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
David Sodman8ef20062015-01-06 09:23:40 -0800411{
Dominik Behr797a3832016-01-11 15:53:11 -0800412 if (!dbus)
Dominik Behrd7112672016-01-20 16:59:34 -0800413 return;
Dominik Behr797a3832016-01-11 15:53:11 -0800414
David Sodman8ef20062015-01-06 09:23:40 -0800415 if (dbus->fd < 0)
416 dbus->fd = dbus_watch_get_unix_fd(dbus->watch);
417
418 if (dbus->fd >= 0) {
419 FD_SET(dbus->fd, read_set);
420 FD_SET(dbus->fd, exception_set);
421 }
David Sodman8ef20062015-01-06 09:23:40 -0800422
Dominik Behrd7112672016-01-20 16:59:34 -0800423 if (dbus->fd > *maxfd)
424 *maxfd = dbus->fd;
David Sodman8ef20062015-01-06 09:23:40 -0800425}
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