/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 2014 Red Hat * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Author: Carlos Garnacho */ #include "config.h" #include #include #include "backends/meta-logical-monitor.h" #include "backends/native/meta-backend-native.h" #include "backends/native/meta-input-device-native.h" #include "backends/native/meta-input-device-tool-native.h" #include "backends/native/meta-input-settings-native.h" G_DEFINE_TYPE (MetaInputSettingsNative, meta_input_settings_native, META_TYPE_INPUT_SETTINGS) static void meta_input_settings_native_set_send_events (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopDeviceSendEvents mode) { enum libinput_config_send_events_mode libinput_mode; struct libinput_device *libinput_device; switch (mode) { case G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED: libinput_mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; break; case G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE: libinput_mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; break; case G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED: libinput_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; break; default: g_assert_not_reached (); } libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; libinput_device_config_send_events_set_mode (libinput_device, libinput_mode); } static void meta_input_settings_native_set_matrix (MetaInputSettings *settings, ClutterInputDevice *device, gfloat matrix[6]) { cairo_matrix_t dev_matrix; if (clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE || meta_input_device_native_get_mapping_mode (device) == META_INPUT_DEVICE_MAPPING_ABSOLUTE) { cairo_matrix_init (&dev_matrix, matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); } else { cairo_matrix_init_identity (&dev_matrix); } g_object_set (device, "device-matrix", &dev_matrix, NULL); } static void meta_input_settings_native_set_speed (MetaInputSettings *settings, ClutterInputDevice *device, gdouble speed) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; libinput_device_config_accel_set_speed (libinput_device, CLAMP (speed, -1, 1)); } static void meta_input_settings_native_set_left_handed (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_left_handed_is_available (libinput_device)) libinput_device_config_left_handed_set (libinput_device, enabled); } static void meta_input_settings_native_set_tap_enabled (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_tap_get_finger_count (libinput_device) > 0) libinput_device_config_tap_set_enabled (libinput_device, enabled ? LIBINPUT_CONFIG_TAP_ENABLED : LIBINPUT_CONFIG_TAP_DISABLED); } static void meta_input_settings_native_set_tap_and_drag_enabled (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_tap_get_finger_count (libinput_device) > 0) libinput_device_config_tap_set_drag_enabled (libinput_device, enabled ? LIBINPUT_CONFIG_DRAG_ENABLED : LIBINPUT_CONFIG_DRAG_DISABLED); } static void meta_input_settings_native_set_tap_and_drag_lock_enabled (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_tap_get_finger_count (libinput_device) > 0) libinput_device_config_tap_set_drag_lock_enabled (libinput_device, enabled ? LIBINPUT_CONFIG_DRAG_LOCK_ENABLED : LIBINPUT_CONFIG_DRAG_LOCK_DISABLED); } static void meta_input_settings_native_set_disable_while_typing (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_dwt_is_available (libinput_device)) libinput_device_config_dwt_set_enabled (libinput_device, enabled ? LIBINPUT_CONFIG_DWT_ENABLED : LIBINPUT_CONFIG_DWT_DISABLED); } static void meta_input_settings_native_set_invert_scroll (MetaInputSettings *settings, ClutterInputDevice *device, gboolean inverted) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_scroll_has_natural_scroll (libinput_device)) libinput_device_config_scroll_set_natural_scroll_enabled (libinput_device, inverted); } static gboolean device_set_scroll_method (struct libinput_device *libinput_device, enum libinput_config_scroll_method method) { enum libinput_config_status status = libinput_device_config_scroll_set_method (libinput_device, method); return status == LIBINPUT_CONFIG_STATUS_SUCCESS; } static gboolean device_set_click_method (struct libinput_device *libinput_device, enum libinput_config_click_method method) { enum libinput_config_status status = libinput_device_config_click_set_method (libinput_device, method); return status == LIBINPUT_CONFIG_STATUS_SUCCESS; } static gboolean device_set_tap_button_map (struct libinput_device *libinput_device, enum libinput_config_tap_button_map map) { enum libinput_config_status status = libinput_device_config_tap_set_button_map (libinput_device, map); return status == LIBINPUT_CONFIG_STATUS_SUCCESS; } static void meta_input_settings_native_set_edge_scroll (MetaInputSettings *settings, ClutterInputDevice *device, gboolean edge_scrolling_enabled) { struct libinput_device *libinput_device; enum libinput_config_scroll_method current, method; libinput_device = meta_input_device_native_get_libinput_device (device); method = edge_scrolling_enabled ? LIBINPUT_CONFIG_SCROLL_EDGE : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; current = libinput_device_config_scroll_get_method (libinput_device); current &= ~LIBINPUT_CONFIG_SCROLL_EDGE; device_set_scroll_method (libinput_device, current | method); } static void meta_input_settings_native_set_two_finger_scroll (MetaInputSettings *settings, ClutterInputDevice *device, gboolean two_finger_scroll_enabled) { struct libinput_device *libinput_device; enum libinput_config_scroll_method current, method; libinput_device = meta_input_device_native_get_libinput_device (device); method = two_finger_scroll_enabled ? LIBINPUT_CONFIG_SCROLL_2FG : LIBINPUT_CONFIG_SCROLL_NO_SCROLL; current = libinput_device_config_scroll_get_method (libinput_device); current &= ~LIBINPUT_CONFIG_SCROLL_2FG; device_set_scroll_method (libinput_device, current | method); } static gboolean meta_input_settings_native_has_two_finger_scroll (MetaInputSettings *settings, ClutterInputDevice *device) { struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return FALSE; return libinput_device_config_scroll_get_methods (libinput_device) & LIBINPUT_CONFIG_SCROLL_2FG; } static void meta_input_settings_native_set_scroll_button (MetaInputSettings *settings, ClutterInputDevice *device, guint button, gboolean button_lock) { struct libinput_device *libinput_device; enum libinput_config_scroll_method method; enum libinput_config_scroll_button_lock_state lock_state; guint evcode; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (button == 0) { method = LIBINPUT_CONFIG_SCROLL_NO_SCROLL; evcode = 0; } else { switch (button) { case 1: evcode = BTN_LEFT; break; case 2: evcode = BTN_MIDDLE; break; case 3: evcode = BTN_RIGHT; break; default: /* Compensate for X11 scroll buttons */ if (button > 7) button -= 4; /* Button is 1-indexed */ evcode = (BTN_LEFT - 1) + button; } method = LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; } if (!device_set_scroll_method (libinput_device, method)) return; libinput_device_config_scroll_set_button (libinput_device, evcode); if (button_lock) lock_state = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED; else lock_state = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; libinput_device_config_scroll_set_button_lock (libinput_device, lock_state); } static void meta_input_settings_native_set_click_method (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopTouchpadClickMethod mode) { enum libinput_config_click_method click_method = 0; struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; switch (mode) { case G_DESKTOP_TOUCHPAD_CLICK_METHOD_DEFAULT: click_method = libinput_device_config_click_get_default_method (libinput_device); break; case G_DESKTOP_TOUCHPAD_CLICK_METHOD_NONE: click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; break; case G_DESKTOP_TOUCHPAD_CLICK_METHOD_AREAS: click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; break; case G_DESKTOP_TOUCHPAD_CLICK_METHOD_FINGERS: click_method = LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; break; default: g_assert_not_reached (); return; } device_set_click_method (libinput_device, click_method); } static void meta_input_settings_native_set_tap_button_map (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopTouchpadTapButtonMap mode) { enum libinput_config_tap_button_map button_map = 0; struct libinput_device *libinput_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_tap_get_finger_count (libinput_device) == 0) return; switch (mode) { case G_DESKTOP_TOUCHPAD_BUTTON_TAP_MAP_DEFAULT: button_map = libinput_device_config_tap_get_default_button_map (libinput_device); break; case G_DESKTOP_TOUCHPAD_BUTTON_TAP_MAP_LRM: button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; break; case G_DESKTOP_TOUCHPAD_BUTTON_TAP_MAP_LMR: button_map = LIBINPUT_CONFIG_TAP_MAP_LMR; break; default: g_assert_not_reached (); return; } device_set_tap_button_map (libinput_device, button_map); } static void meta_input_settings_native_set_keyboard_repeat (MetaInputSettings *settings, gboolean enabled, guint delay, guint interval) { ClutterSeat *seat; seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); meta_seat_native_set_keyboard_repeat (META_SEAT_NATIVE (seat), enabled, delay, interval); } static void set_device_accel_profile (ClutterInputDevice *device, GDesktopPointerAccelProfile profile) { struct libinput_device *libinput_device; enum libinput_config_accel_profile libinput_profile; uint32_t profiles; libinput_device = meta_input_device_native_get_libinput_device (device); switch (profile) { case G_DESKTOP_POINTER_ACCEL_PROFILE_FLAT: libinput_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; break; case G_DESKTOP_POINTER_ACCEL_PROFILE_ADAPTIVE: libinput_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; break; default: g_warn_if_reached (); case G_DESKTOP_POINTER_ACCEL_PROFILE_DEFAULT: libinput_profile = libinput_device_config_accel_get_default_profile (libinput_device); } profiles = libinput_device_config_accel_get_profiles (libinput_device); if ((profiles & libinput_profile) == 0) { libinput_profile = libinput_device_config_accel_get_default_profile (libinput_device); } libinput_device_config_accel_set_profile (libinput_device, libinput_profile); } static gboolean has_udev_property (ClutterInputDevice *device, const char *property) { struct libinput_device *libinput_device; struct udev_device *udev_device; struct udev_device *parent_udev_device; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return FALSE; udev_device = libinput_device_get_udev_device (libinput_device); if (!udev_device) return FALSE; if (NULL != udev_device_get_property_value (udev_device, property)) { udev_device_unref (udev_device); return TRUE; } parent_udev_device = udev_device_get_parent (udev_device); udev_device_unref (udev_device); if (!parent_udev_device) return FALSE; if (NULL != udev_device_get_property_value (parent_udev_device, property)) return TRUE; return FALSE; } static gboolean is_mouse_device (ClutterInputDevice *device) { return (has_udev_property (device, "ID_INPUT_MOUSE") && !has_udev_property (device, "ID_INPUT_POINTINGSTICK")); } static gboolean meta_input_settings_native_is_touchpad_device (MetaInputSettings *settings, ClutterInputDevice *device) { return has_udev_property (device, "ID_INPUT_TOUCHPAD"); } static gboolean meta_input_settings_native_is_trackball_device (MetaInputSettings *settings, ClutterInputDevice *device) { return has_udev_property (device, "ID_INPUT_TRACKBALL"); } static void meta_input_settings_native_set_mouse_accel_profile (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopPointerAccelProfile profile) { if (!is_mouse_device (device)) return; set_device_accel_profile (device, profile); } static void meta_input_settings_native_set_trackball_accel_profile (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopPointerAccelProfile profile) { if (!meta_input_settings_native_is_trackball_device (settings, device)) return; set_device_accel_profile (device, profile); } static void meta_input_settings_native_set_tablet_mapping (MetaInputSettings *settings, ClutterInputDevice *device, GDesktopTabletMapping mapping) { MetaInputDeviceMapping dev_mapping; if (mapping == G_DESKTOP_TABLET_MAPPING_ABSOLUTE) dev_mapping = META_INPUT_DEVICE_MAPPING_ABSOLUTE; else if (mapping == G_DESKTOP_TABLET_MAPPING_RELATIVE) dev_mapping = META_INPUT_DEVICE_MAPPING_RELATIVE; else return; meta_input_device_native_set_mapping_mode (device, dev_mapping); } static void meta_input_settings_native_set_tablet_keep_aspect (MetaInputSettings *settings, ClutterInputDevice *device, MetaLogicalMonitor *logical_monitor, gboolean keep_aspect) { double aspect_ratio = 0; if (meta_input_device_native_get_mapping_mode (device) == META_INPUT_DEVICE_MAPPING_RELATIVE) keep_aspect = FALSE; if (keep_aspect) { int width, height; if (logical_monitor) { width = logical_monitor->rect.width; height = logical_monitor->rect.height; } else { MetaMonitorManager *monitor_manager; MetaBackend *backend; backend = meta_get_backend (); monitor_manager = meta_backend_get_monitor_manager (backend); meta_monitor_manager_get_screen_size (monitor_manager, &width, &height); } aspect_ratio = (double) width / height; } g_object_set (device, "output-aspect-ratio", aspect_ratio, NULL); } static void meta_input_settings_native_set_tablet_area (MetaInputSettings *settings, ClutterInputDevice *device, gdouble padding_left, gdouble padding_right, gdouble padding_top, gdouble padding_bottom) { struct libinput_device *libinput_device; gfloat scale_x; gfloat scale_y; gfloat offset_x; gfloat offset_y; scale_x = 1. / (1. - (padding_left + padding_right)); scale_y = 1. / (1. - (padding_top + padding_bottom)); offset_x = -padding_left * scale_x; offset_y = -padding_top * scale_y; gfloat matrix[6] = { scale_x, 0., offset_x, 0., scale_y, offset_y }; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device || !libinput_device_config_calibration_has_matrix (libinput_device)) return; libinput_device_config_calibration_set_matrix (libinput_device, matrix); } static void meta_input_settings_native_set_stylus_pressure (MetaInputSettings *settings, ClutterInputDevice *device, ClutterInputDeviceTool *tool, const gint curve[4]) { gdouble pressure_curve[4]; pressure_curve[0] = (gdouble) curve[0] / 100; pressure_curve[1] = (gdouble) curve[1] / 100; pressure_curve[2] = (gdouble) curve[2] / 100; pressure_curve[3] = (gdouble) curve[3] / 100; meta_input_device_tool_native_set_pressure_curve (tool, pressure_curve); } static guint action_to_evcode (GDesktopStylusButtonAction action) { switch (action) { case G_DESKTOP_STYLUS_BUTTON_ACTION_MIDDLE: return BTN_STYLUS; case G_DESKTOP_STYLUS_BUTTON_ACTION_RIGHT: return BTN_STYLUS2; case G_DESKTOP_STYLUS_BUTTON_ACTION_BACK: return BTN_BACK; case G_DESKTOP_STYLUS_BUTTON_ACTION_FORWARD: return BTN_FORWARD; case G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT: default: return 0; } } static void meta_input_settings_native_set_stylus_button_map (MetaInputSettings *settings, ClutterInputDevice *device, ClutterInputDeviceTool *tool, GDesktopStylusButtonAction primary, GDesktopStylusButtonAction secondary, GDesktopStylusButtonAction tertiary) { meta_input_device_tool_native_set_button_code (tool, CLUTTER_BUTTON_MIDDLE, action_to_evcode (primary)); meta_input_device_tool_native_set_button_code (tool, CLUTTER_BUTTON_SECONDARY, action_to_evcode (secondary)); meta_input_device_tool_native_set_button_code (tool, 8, /* Back */ action_to_evcode (tertiary)); } static void meta_input_settings_native_set_mouse_middle_click_emulation (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; if (!is_mouse_device (device)) return; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_middle_emulation_is_available (libinput_device)) libinput_device_config_middle_emulation_set_enabled (libinput_device, enabled); } static void meta_input_settings_native_set_touchpad_middle_click_emulation (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; if (!meta_input_settings_native_is_touchpad_device (settings, device)) return; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_middle_emulation_is_available (libinput_device)) libinput_device_config_middle_emulation_set_enabled (libinput_device, enabled); } static void meta_input_settings_native_set_trackball_middle_click_emulation (MetaInputSettings *settings, ClutterInputDevice *device, gboolean enabled) { struct libinput_device *libinput_device; if (!meta_input_settings_native_is_trackball_device (settings, device)) return; libinput_device = meta_input_device_native_get_libinput_device (device); if (!libinput_device) return; if (libinput_device_config_middle_emulation_is_available (libinput_device)) libinput_device_config_middle_emulation_set_enabled (libinput_device, enabled); } static void meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass) { MetaInputSettingsClass *input_settings_class = META_INPUT_SETTINGS_CLASS (klass); input_settings_class->set_send_events = meta_input_settings_native_set_send_events; input_settings_class->set_matrix = meta_input_settings_native_set_matrix; input_settings_class->set_speed = meta_input_settings_native_set_speed; input_settings_class->set_left_handed = meta_input_settings_native_set_left_handed; input_settings_class->set_tap_enabled = meta_input_settings_native_set_tap_enabled; input_settings_class->set_tap_button_map = meta_input_settings_native_set_tap_button_map; input_settings_class->set_tap_and_drag_enabled = meta_input_settings_native_set_tap_and_drag_enabled; input_settings_class->set_tap_and_drag_lock_enabled = meta_input_settings_native_set_tap_and_drag_lock_enabled; input_settings_class->set_invert_scroll = meta_input_settings_native_set_invert_scroll; input_settings_class->set_edge_scroll = meta_input_settings_native_set_edge_scroll; input_settings_class->set_two_finger_scroll = meta_input_settings_native_set_two_finger_scroll; input_settings_class->set_scroll_button = meta_input_settings_native_set_scroll_button; input_settings_class->set_click_method = meta_input_settings_native_set_click_method; input_settings_class->set_keyboard_repeat = meta_input_settings_native_set_keyboard_repeat; input_settings_class->set_disable_while_typing = meta_input_settings_native_set_disable_while_typing; input_settings_class->set_tablet_mapping = meta_input_settings_native_set_tablet_mapping; input_settings_class->set_tablet_keep_aspect = meta_input_settings_native_set_tablet_keep_aspect; input_settings_class->set_tablet_area = meta_input_settings_native_set_tablet_area; input_settings_class->set_mouse_accel_profile = meta_input_settings_native_set_mouse_accel_profile; input_settings_class->set_trackball_accel_profile = meta_input_settings_native_set_trackball_accel_profile; input_settings_class->set_stylus_pressure = meta_input_settings_native_set_stylus_pressure; input_settings_class->set_stylus_button_map = meta_input_settings_native_set_stylus_button_map; input_settings_class->set_mouse_middle_click_emulation = meta_input_settings_native_set_mouse_middle_click_emulation; input_settings_class->set_touchpad_middle_click_emulation = meta_input_settings_native_set_touchpad_middle_click_emulation; input_settings_class->set_trackball_middle_click_emulation = meta_input_settings_native_set_trackball_middle_click_emulation; input_settings_class->has_two_finger_scroll = meta_input_settings_native_has_two_finger_scroll; input_settings_class->is_trackball_device = meta_input_settings_native_is_trackball_device; } static void meta_input_settings_native_init (MetaInputSettingsNative *settings) { }