forked from enlightenment/enlightenment
481 lines
14 KiB
C
481 lines
14 KiB
C
//
|
|
// Created by raffaele on 01/05/19.
|
|
//
|
|
//#include <Ecore_X.h>
|
|
#include "convertible_logging.h"
|
|
#include "accelerometer-orientation.h"
|
|
#include "dbus_acceleration.h"
|
|
#include "e_mod_main.h"
|
|
#include "input_rotation.h"
|
|
|
|
static DbusAccelerometer* accelerometer_dbus;
|
|
|
|
|
|
/**
|
|
* Callback definition to handle the request of the hasAccelerometer property of DBUS interface net.hadess.SensorProxy
|
|
* @param data DbusAccelerometer
|
|
* @param msg The message
|
|
* @param pending
|
|
*/
|
|
static void
|
|
on_has_accelerometer(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
const char *errname, *errmsg;
|
|
Eina_Bool has_accelerometer = EINA_FALSE;
|
|
Eldbus_Message_Iter *variant = NULL;
|
|
|
|
if (eldbus_message_error_get(msg, &errname, &errmsg))
|
|
{
|
|
ERR("Error: %s %s", errname, errmsg);
|
|
}
|
|
|
|
_access_bool_property(msg, &variant, &has_accelerometer);
|
|
DbusAccelerometer *accelerometer = data;
|
|
accelerometer->has_accelerometer = has_accelerometer;
|
|
DBG("Has Accelerometer: %d", accelerometer->has_accelerometer);
|
|
}
|
|
|
|
|
|
DbusAccelerometer*
|
|
sensor_proxy_init(void)
|
|
{
|
|
// Initialise DBUS component
|
|
if (accelerometer_dbus)
|
|
{
|
|
INF("We already have a struct filled");
|
|
return accelerometer_dbus;
|
|
}
|
|
accelerometer_dbus = calloc(1, sizeof(DbusAccelerometer));
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(accelerometer_dbus, NULL);
|
|
|
|
// The next line is probably redundant
|
|
accelerometer_dbus->orientation = UNDEFINED;
|
|
|
|
INF("Getting dbus interfaces");
|
|
accelerometer_dbus->sensor_proxy = get_dbus_interface(EFL_DBUS_ACC_IFACE);
|
|
accelerometer_dbus->sensor_proxy_properties = get_dbus_interface(ELDBUS_FDO_INTERFACE_PROPERTIES);
|
|
if (accelerometer_dbus->sensor_proxy == NULL)
|
|
{
|
|
ERR("Unable to get the proxy for interface %s", EFL_DBUS_ACC_IFACE);
|
|
return accelerometer_dbus;
|
|
}
|
|
|
|
accelerometer_dbus->pending_has_orientation = eldbus_proxy_property_get(accelerometer_dbus->sensor_proxy,
|
|
"HasAccelerometer", on_has_accelerometer,
|
|
accelerometer_dbus);
|
|
if (!accelerometer_dbus->pending_has_orientation)
|
|
{
|
|
ERR("Error: could not get property HasAccelerometer");
|
|
}
|
|
|
|
// Claim the accelerometer_dbus
|
|
accelerometer_dbus->pending_acc_claim = eldbus_proxy_call(accelerometer_dbus->sensor_proxy, "ClaimAccelerometer",
|
|
on_accelerometer_claimed, accelerometer_dbus, -1, "");
|
|
|
|
if (!accelerometer_dbus->pending_acc_claim)
|
|
{
|
|
ERR("Error: could not call ClaimAccelerometer");
|
|
}
|
|
|
|
return accelerometer_dbus;
|
|
}
|
|
|
|
void
|
|
sensor_proxy_shutdown(void)
|
|
{
|
|
INF("Removing signal handler dbus_property_changed_sh");
|
|
eldbus_signal_handler_del(accelerometer_dbus->dbus_property_changed_sh);
|
|
|
|
// TODO Should to this and wait for the release before continuing
|
|
INF("Freeing convertible resources");
|
|
accelerometer_dbus->pending_acc_crelease = eldbus_proxy_call(accelerometer_dbus->sensor_proxy, "ReleaseAccelerometer", on_accelerometer_released, accelerometer_dbus, -1, "");
|
|
if (accelerometer_dbus)
|
|
{
|
|
e_object_del(E_OBJECT(accelerometer_dbus));
|
|
free(accelerometer_dbus);
|
|
accelerometer_dbus = NULL;
|
|
}
|
|
|
|
DBG("Shutting down ELDBUS");
|
|
eldbus_shutdown();
|
|
}
|
|
|
|
int
|
|
_convertible_rotation_get(const enum screen_rotation orientation);
|
|
|
|
int
|
|
_is_device_a_touch_pointer(int dev_counter, int num_properties, char **iterator);
|
|
|
|
/**
|
|
* Helper to get the interface
|
|
* */
|
|
statis Eldbus_Proxy *
|
|
get_dbus_interface(const char *IFACE)
|
|
{
|
|
DBG("Working on interface: %s", IFACE);
|
|
Eldbus_Connection *conn;
|
|
Eldbus_Object *obj;
|
|
Eldbus_Proxy *sensor_proxy;
|
|
|
|
conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
|
|
if (!conn)
|
|
{
|
|
ERR("Error: could not get system bus");
|
|
return NULL;
|
|
}
|
|
obj = eldbus_object_get(conn, EFL_DBUS_ACC_BUS, EFL_DBUS_ACC_PATH);
|
|
if (!obj)
|
|
{
|
|
ERR("Error: could not get object");
|
|
return NULL;
|
|
}
|
|
sensor_proxy = eldbus_proxy_get(obj, IFACE);
|
|
if (!sensor_proxy)
|
|
{
|
|
ERR("Error: could not get proxy for interface %s", IFACE);
|
|
return NULL;
|
|
}
|
|
|
|
return sensor_proxy;
|
|
}
|
|
|
|
/**
|
|
* Helper function to extract ta string property from the message
|
|
* @param msg The message coming from the get property invocation
|
|
* @param variant
|
|
* @return Enum specifying the orientation. UNDEFINED by default
|
|
*/
|
|
enum screen_rotation
|
|
_access_string_property(const Eldbus_Message *msg, Eldbus_Message_Iter **variant)
|
|
{
|
|
enum screen_rotation rotation = UNDEFINED;
|
|
char *type = NULL;
|
|
|
|
if (!eldbus_message_arguments_get(msg, "v", variant))
|
|
{
|
|
WARN("Error getting arguments.");
|
|
}
|
|
type = eldbus_message_iter_signature_get((*variant));
|
|
if (type == NULL)
|
|
{
|
|
WARN("Unable to get the type.");
|
|
return rotation;
|
|
}
|
|
|
|
type = eldbus_message_iter_signature_get((*variant));
|
|
if (type[1])
|
|
{
|
|
WARN("It is a complex type, not handle yet.");
|
|
}
|
|
if (type[0] != 's')
|
|
{
|
|
WARN("Expected type is string(s).");
|
|
}
|
|
const char **string_property_value = calloc(PATH_MAX, sizeof(char));
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(string_property_value, EINA_FALSE);
|
|
if (!eldbus_message_iter_arguments_get((*variant), "s", string_property_value))
|
|
{
|
|
WARN("error in eldbus_message_iter_arguments_get()");
|
|
}
|
|
|
|
if (!strcmp(ACCELEROMETER_ORIENTATION_RIGHT, *string_property_value))
|
|
rotation = RIGHT_UP;
|
|
if (!strcmp(ACCELEROMETER_ORIENTATION_LEFT, *string_property_value))
|
|
rotation = LEFT_UP;
|
|
if (!strcmp(ACCELEROMETER_ORIENTATION_BOTTOM, *string_property_value))
|
|
rotation = FLIPPED;
|
|
if (!strcmp(ACCELEROMETER_ORIENTATION_NORMAL, *string_property_value))
|
|
rotation = NORMAL;
|
|
|
|
free(type);
|
|
free(string_property_value);
|
|
return rotation;
|
|
}
|
|
|
|
/**
|
|
* Helper function to extract ta boolean property from the message
|
|
* @param msg The message coming from the get property invocation
|
|
* @param variant
|
|
* @param boolean_property_value The boolean property pointer where the value should be stored, if read
|
|
* @return
|
|
*/
|
|
Eina_Bool
|
|
_access_bool_property(const Eldbus_Message *msg, Eldbus_Message_Iter **variant, Eina_Bool *boolean_property_value)
|
|
{
|
|
char *type;
|
|
Eina_Bool res = EINA_TRUE;
|
|
|
|
if (!eldbus_message_arguments_get(msg, "v", variant))
|
|
{
|
|
WARN("Error getting arguments.");
|
|
res = EINA_FALSE;
|
|
}
|
|
type = eldbus_message_iter_signature_get((*variant));
|
|
if (type == NULL)
|
|
{
|
|
WARN("Unable to get the type.");
|
|
res = EINA_FALSE;
|
|
return res;
|
|
}
|
|
|
|
if (type[1])
|
|
{
|
|
WARN("It is a complex type, not handle yet.");
|
|
res = EINA_FALSE;
|
|
}
|
|
if (type[0] != 'b')
|
|
{
|
|
WARN("Expected type is int.");
|
|
res = EINA_FALSE;
|
|
}
|
|
if (!eldbus_message_iter_arguments_get((*variant), "b", boolean_property_value))
|
|
{
|
|
WARN("error in eldbus_message_iter_arguments_get()");
|
|
res = EINA_FALSE;
|
|
}
|
|
free(type);
|
|
return res;
|
|
}
|
|
|
|
void
|
|
on_accelerometer_orientation(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
INF("New orientation received");
|
|
Instance *inst = (Instance *) data;
|
|
|
|
if (inst->locked_position == EINA_TRUE)
|
|
{
|
|
WARN("Locked position. Ignoring rotation");
|
|
return;
|
|
}
|
|
|
|
|
|
const char *errname, *errmsg;
|
|
enum screen_rotation orientation;
|
|
Eldbus_Message_Iter *variant = NULL;
|
|
|
|
if (eldbus_message_error_get(msg, &errname, &errmsg))
|
|
{
|
|
ERR("Error: %s %s", errname, errmsg);
|
|
return;
|
|
}
|
|
|
|
orientation = _access_string_property(msg, &variant);
|
|
if (orientation == UNDEFINED)
|
|
{
|
|
INF("Failed to retrieve the orientation from dbus message");
|
|
return;
|
|
}
|
|
|
|
inst->accelerometer->orientation = orientation;
|
|
DBG("Current Orientation: %d", inst->accelerometer->orientation);
|
|
|
|
if (inst->randr2_ids == NULL)
|
|
ERR("Screen not set.");
|
|
else
|
|
{
|
|
Eina_List *l;
|
|
char *randr_id = NULL;
|
|
EINA_LIST_FOREACH(inst->randr2_ids, l, randr_id)
|
|
{
|
|
_fetch_and_rotate_screen(randr_id, orientation);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
_convertible_rotation_get(const enum screen_rotation orientation)
|
|
{
|
|
switch (orientation)
|
|
{
|
|
case NORMAL: return 0;
|
|
case LEFT_UP: return 90;
|
|
case FLIPPED: return 180;
|
|
case RIGHT_UP: return 270;
|
|
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
const float *
|
|
_get_matrix_rotation_transformation(int rotation)
|
|
{
|
|
const float *transformation;
|
|
switch (rotation) {
|
|
case 90:
|
|
transformation = MATRIX_ROTATION_90;
|
|
break;
|
|
case 180:
|
|
transformation = MATRIX_ROTATION_180;
|
|
break;
|
|
case 270:
|
|
transformation = MATRIX_ROTATION_270;
|
|
break;
|
|
default:
|
|
transformation = MATRIX_ROTATION_IDENTITY;
|
|
}
|
|
return transformation;
|
|
}
|
|
|
|
int
|
|
_fetch_X_device_input_number(void)
|
|
{
|
|
// I should get the touchscreen associated with the screen probably by looking at the classes of the input devices
|
|
// I need to submit my patch to add getters for other XIDeviceInfo fields, like raster mentioned in his commit.
|
|
const char *dev_name;
|
|
char **property_name;
|
|
int dev_num = ecore_x_input_device_num_get();
|
|
int dev_number = -1;
|
|
|
|
for (int dev_counter = 0; dev_counter < dev_num; dev_counter++)
|
|
{
|
|
dev_name = ecore_x_input_device_name_get(dev_counter);
|
|
// Less horrible hack that relies on the presence of a property containing the work Calibration
|
|
DBG("Found device with name %s", dev_name);
|
|
int num_properties;
|
|
property_name = ecore_x_input_device_properties_list(dev_counter, &num_properties);
|
|
DBG("Found %d properties", num_properties);
|
|
char **iterator = property_name;
|
|
int is_correct_device = _is_device_a_touch_pointer(dev_counter, num_properties, iterator);
|
|
if (is_correct_device == EINA_FALSE)
|
|
continue;
|
|
iterator = property_name;
|
|
for (int i = 0; i < num_properties; i++)
|
|
{
|
|
if (!strcmp(*iterator, CTM_name))
|
|
{
|
|
dev_number = dev_counter;
|
|
DBG("Setting device: %d", dev_number);
|
|
}
|
|
iterator++;
|
|
}
|
|
}
|
|
|
|
return dev_number;
|
|
}
|
|
|
|
int
|
|
_is_device_a_touch_pointer(int dev_counter, int num_properties, char **iterator)
|
|
{
|
|
// Looking for a device with either a libinput property for calibration or the old evdev Axlis labels property.
|
|
int is_correct_device = EINA_FALSE;
|
|
for (int i = 0; i < num_properties; i++)
|
|
{
|
|
if (strstr(*iterator, "libinput Calibration Matrix"))
|
|
is_correct_device = EINA_TRUE;
|
|
if (strstr(*iterator, "Axis Labels"))
|
|
{
|
|
int num_ret, unit_size_ret;
|
|
Ecore_X_Atom format_ret;
|
|
char *result = ecore_x_input_device_property_get(dev_counter, *iterator, &num_ret, &format_ret, &unit_size_ret);
|
|
if (result) {
|
|
// TODO Shall check for the value "Abs MT Position"
|
|
}
|
|
DBG("Looks like I found a device with calibration capabilities");
|
|
is_correct_device = EINA_TRUE;
|
|
}
|
|
iterator++;
|
|
}
|
|
return is_correct_device;
|
|
}
|
|
|
|
/**
|
|
* Fetch a screen from its ID and rotate it according to the rotation parameter
|
|
* @param randr_id The randr2 id
|
|
* @param rotation The expected rotation
|
|
*/
|
|
void
|
|
_fetch_and_rotate_screen(const char* randr_id, enum screen_rotation orientation)
|
|
{
|
|
DBG("Working on screen %s", randr_id);
|
|
E_Randr2_Screen *rotatable_screen = e_randr2_screen_id_find(randr_id);
|
|
E_Config_Randr2_Screen *screen_randr_cfg = e_randr2_config_screen_find(rotatable_screen, e_randr2_cfg);
|
|
int rotation = _convertible_rotation_get(orientation);
|
|
DBG("Screen %s is going to be rotated to %d", randr_id, rotation);
|
|
|
|
if (rotation == screen_randr_cfg->rotation)
|
|
{
|
|
WARN("Screen %s is already rotated to %d degrees", randr_id, rotation);
|
|
} else
|
|
{
|
|
screen_randr_cfg->rotation = rotation;
|
|
e_randr2_config_apply();
|
|
DBG("Screen %s rotated to %d", randr_id, rotation);
|
|
|
|
int x_dev_num = _fetch_X_device_input_number();
|
|
if (x_dev_num == -1)
|
|
{
|
|
ERR("Unable to find a pointer device with coordinate transformation capabilities");
|
|
return;
|
|
}
|
|
DBG("Rotating input number %d", x_dev_num);
|
|
|
|
int num_ret, unit_size_ret;
|
|
Ecore_X_Atom format_ret;
|
|
char *result = NULL;
|
|
TransformationMatrix *matrix = calloc(1, sizeof(TransformationMatrix));
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(matrix, NULL);
|
|
result = ecore_x_input_device_property_get(x_dev_num, CTM_name, &num_ret, &format_ret, &unit_size_ret);
|
|
if (result)
|
|
{
|
|
|
|
DBG("Device with coordinates transformation matrix");
|
|
// format_ret of 116 -> ECORE_X_ATOM_FLOAT
|
|
// num_ret of 9 -> 9 (float) to read
|
|
// unit_size_ret of 32 -> each float is 32 bits
|
|
memcpy(matrix->values, result, sizeof(matrix->values));
|
|
const float * rotation_matrix_2d = _get_matrix_rotation_transformation(rotation);
|
|
memcpy(matrix->values, rotation_matrix_2d, 6 * sizeof(*rotation_matrix_2d));
|
|
ecore_x_input_device_property_set(x_dev_num, CTM_name, matrix->values, num_ret, format_ret, unit_size_ret);
|
|
|
|
DBG("Input device %d rotated to %d", x_dev_num, rotation);
|
|
} else {
|
|
ERR("Unable to fetch coordinates transformation matrix for device %d", x_dev_num);
|
|
}
|
|
free(matrix);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Callback definition to handle the execution of the ClaimAccelerometer() method of DBUS
|
|
* interface net.hadess.SensorProxy
|
|
* @param data not used
|
|
* @param msg The message
|
|
* @param pending
|
|
*/
|
|
static void
|
|
on_accelerometer_claimed(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
const char *errname, *errmsg;
|
|
|
|
INF("Going to claim the accelerometer_dbus");
|
|
if (eldbus_message_error_get(msg, &errname, &errmsg))
|
|
{
|
|
ERR("Error: %s %s", errname, errmsg);
|
|
return;
|
|
}
|
|
INF("Accelerometer claimed");
|
|
}
|
|
|
|
|
|
/**
|
|
* Callback definition to handle the execution of the ReleaseAccelerometer() method of DBUS
|
|
* interface net.hadess.SensorProxy
|
|
* @param data not used
|
|
* @param msg The message
|
|
* @param pending
|
|
*/
|
|
static void
|
|
on_accelerometer_released(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)
|
|
{
|
|
const char *errname, *errmsg;
|
|
|
|
INF("Going to release the accelerometer_dbus");
|
|
if (eldbus_message_error_get(msg, &errname, &errmsg))
|
|
{
|
|
ERR("Error: %s %s", errname, errmsg);
|
|
return;
|
|
}
|
|
INF("Accelerometer released");
|
|
}
|