a48c9d6cd9
When no output was specified, the screen limit was used to calculate the aspect ratio. The screen limit, however, is either just an arbitrary number if no screen limit is applicable, or a hardware graphics buffer limit, which has nothing to do with anything actually displayed. Change it to use the screen size instead, to get something that makes more sense when no output is found. https://bugzilla.gnome.org/show_bug.cgi?id=779745
777 lines
25 KiB
C
777 lines
25 KiB
C
/* -*- 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 <carlosg@gnome.org>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "meta-backend-x11.h"
|
|
#include "meta-input-settings-x11.h"
|
|
|
|
#include <string.h>
|
|
#include <gdk/gdkx.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/extensions/XInput2.h>
|
|
#include <X11/XKBlib.h>
|
|
#ifdef HAVE_LIBGUDEV
|
|
#include <gudev/gudev.h>
|
|
#endif
|
|
|
|
#include <meta/errors.h>
|
|
|
|
typedef struct _MetaInputSettingsX11Private
|
|
{
|
|
#ifdef HAVE_LIBGUDEV
|
|
GUdevClient *udev_client;
|
|
#endif
|
|
} MetaInputSettingsX11Private;
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaInputSettingsX11, meta_input_settings_x11,
|
|
META_TYPE_INPUT_SETTINGS)
|
|
|
|
enum {
|
|
SCROLL_METHOD_FIELD_2FG,
|
|
SCROLL_METHOD_FIELD_EDGE,
|
|
SCROLL_METHOD_FIELD_BUTTON,
|
|
SCROLL_METHOD_NUM_FIELDS
|
|
};
|
|
|
|
static void *
|
|
get_property (ClutterInputDevice *device,
|
|
const gchar *property,
|
|
Atom type,
|
|
int format,
|
|
gulong nitems)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
gulong nitems_ret, bytes_after_ret;
|
|
int rc, device_id, format_ret;
|
|
Atom property_atom, type_ret;
|
|
guchar *data_ret = NULL;
|
|
|
|
property_atom = XInternAtom (xdisplay, property, True);
|
|
if (!property_atom)
|
|
return NULL;
|
|
|
|
device_id = clutter_input_device_get_device_id (device);
|
|
|
|
rc = XIGetProperty (xdisplay, device_id, property_atom,
|
|
0, 10, False, type, &type_ret, &format_ret,
|
|
&nitems_ret, &bytes_after_ret, &data_ret);
|
|
if (rc == Success && type_ret == type && format_ret == format && nitems_ret >= nitems)
|
|
{
|
|
if (nitems_ret > nitems)
|
|
g_warning ("Property '%s' for device '%s' returned %lu items, expected %lu",
|
|
property, clutter_input_device_get_device_name (device), nitems_ret, nitems);
|
|
return data_ret;
|
|
}
|
|
|
|
meta_XFree (data_ret);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
change_property (ClutterInputDevice *device,
|
|
const gchar *property,
|
|
Atom type,
|
|
int format,
|
|
void *data,
|
|
gulong nitems)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
int device_id;
|
|
Atom property_atom;
|
|
guchar *data_ret;
|
|
|
|
property_atom = XInternAtom (xdisplay, property, True);
|
|
if (!property_atom)
|
|
return;
|
|
|
|
device_id = clutter_input_device_get_device_id (device);
|
|
|
|
data_ret = get_property (device, property, type, format, nitems);
|
|
if (!data_ret)
|
|
return;
|
|
|
|
XIChangeProperty (xdisplay, device_id, property_atom, type,
|
|
format, XIPropModeReplace, data, nitems);
|
|
meta_XFree (data_ret);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_send_events (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
GDesktopDeviceSendEvents mode)
|
|
{
|
|
guchar values[2] = { 0 }; /* disabled, disabled-on-external-mouse */
|
|
guchar *available;
|
|
|
|
available = get_property (device, "libinput Send Events Modes Available",
|
|
XA_INTEGER, 8, 2);
|
|
if (!available)
|
|
return;
|
|
|
|
switch (mode)
|
|
{
|
|
case G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED:
|
|
values[0] = 1;
|
|
break;
|
|
case G_DESKTOP_DEVICE_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
|
|
values[1] = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if ((values[0] && !available[0]) || (values[1] && !available[1]))
|
|
g_warning ("Device '%s' does not support sendevents mode %d\n",
|
|
clutter_input_device_get_device_name (device), mode);
|
|
else
|
|
change_property (device, "libinput Send Events Mode Enabled",
|
|
XA_INTEGER, 8, &values, 2);
|
|
|
|
meta_XFree (available);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_matrix (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gfloat matrix[6])
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
gfloat full_matrix[9] = { matrix[0], matrix[1], matrix[2],
|
|
matrix[3], matrix[4], matrix[5],
|
|
0, 0, 1 };
|
|
|
|
change_property (device, "Coordinate Transformation Matrix",
|
|
XInternAtom (xdisplay, "FLOAT", False),
|
|
32, &full_matrix, 9);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_speed (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gdouble speed)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
gfloat value = speed;
|
|
|
|
change_property (device, "libinput Accel Speed",
|
|
XInternAtom (xdisplay, "FLOAT", False),
|
|
32, &value, 1);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_left_handed (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gboolean enabled)
|
|
{
|
|
guchar value;
|
|
|
|
if (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE)
|
|
{
|
|
value = enabled ? 3 : 0;
|
|
change_property (device, "Wacom Rotation",
|
|
XA_INTEGER, 8, &value, 1);
|
|
}
|
|
else
|
|
{
|
|
value = enabled ? 1 : 0;
|
|
change_property (device, "libinput Left Handed Enabled",
|
|
XA_INTEGER, 8, &value, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_tap_enabled (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gboolean enabled)
|
|
{
|
|
guchar value = (enabled) ? 1 : 0;
|
|
|
|
change_property (device, "libinput Tapping Enabled",
|
|
XA_INTEGER, 8, &value, 1);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_invert_scroll (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gboolean inverted)
|
|
{
|
|
guchar value = (inverted) ? 1 : 0;
|
|
|
|
change_property (device, "libinput Natural Scrolling Enabled",
|
|
XA_INTEGER, 8, &value, 1);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_edge_scroll (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gboolean edge_scroll_enabled)
|
|
{
|
|
guchar values[SCROLL_METHOD_NUM_FIELDS] = { 0 }; /* 2fg, edge, button. The last value is unused */
|
|
guchar *current = NULL;
|
|
guchar *available = NULL;
|
|
|
|
available = get_property (device, "libinput Scroll Methods Available",
|
|
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
|
if (!available || !available[SCROLL_METHOD_FIELD_EDGE])
|
|
goto out;
|
|
|
|
current = get_property (device, "libinput Scroll Method Enabled",
|
|
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
|
if (!current)
|
|
goto out;
|
|
|
|
memcpy (values, current, SCROLL_METHOD_NUM_FIELDS);
|
|
|
|
values[SCROLL_METHOD_FIELD_EDGE] = !!edge_scroll_enabled;
|
|
change_property (device, "libinput Scroll Method Enabled",
|
|
XA_INTEGER, 8, &values, SCROLL_METHOD_NUM_FIELDS);
|
|
out:
|
|
meta_XFree (current);
|
|
meta_XFree (available);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_two_finger_scroll (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gboolean two_finger_scroll_enabled)
|
|
{
|
|
guchar values[SCROLL_METHOD_NUM_FIELDS] = { 0 }; /* 2fg, edge, button. The last value is unused */
|
|
guchar *current = NULL;
|
|
guchar *available = NULL;
|
|
|
|
available = get_property (device, "libinput Scroll Methods Available",
|
|
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
|
if (!available || !available[SCROLL_METHOD_FIELD_2FG])
|
|
goto out;
|
|
|
|
current = get_property (device, "libinput Scroll Method Enabled",
|
|
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
|
if (!current)
|
|
goto out;
|
|
|
|
memcpy (values, current, SCROLL_METHOD_NUM_FIELDS);
|
|
|
|
values[SCROLL_METHOD_FIELD_2FG] = !!two_finger_scroll_enabled;
|
|
change_property (device, "libinput Scroll Method Enabled",
|
|
XA_INTEGER, 8, &values, SCROLL_METHOD_NUM_FIELDS);
|
|
out:
|
|
meta_XFree (current);
|
|
meta_XFree (available);
|
|
}
|
|
|
|
static gboolean
|
|
meta_input_settings_x11_has_two_finger_scroll (MetaInputSettings *settings,
|
|
ClutterInputDevice *device)
|
|
{
|
|
guchar *available = NULL;
|
|
gboolean has_two_finger = TRUE;
|
|
|
|
available = get_property (device, "libinput Scroll Methods Available",
|
|
XA_INTEGER, 8, SCROLL_METHOD_NUM_FIELDS);
|
|
if (!available || !available[SCROLL_METHOD_FIELD_2FG])
|
|
has_two_finger = FALSE;
|
|
|
|
meta_XFree (available);
|
|
return has_two_finger;
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_scroll_button (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
guint button)
|
|
{
|
|
change_property (device, "libinput Button Scrolling Button",
|
|
XA_INTEGER, 32, &button, 1);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_click_method (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
GDesktopTouchpadClickMethod mode)
|
|
{
|
|
guchar values[2] = { 0 }; /* buttonareas, clickfinger */
|
|
guchar *defaults, *available;
|
|
|
|
available = get_property (device, "libinput Click Methods Available",
|
|
XA_INTEGER, 8, 2);
|
|
if (!available)
|
|
return;
|
|
|
|
switch (mode)
|
|
{
|
|
case G_DESKTOP_TOUCHPAD_CLICK_METHOD_DEFAULT:
|
|
defaults = get_property (device, "libinput Click Method Enabled Default",
|
|
XA_INTEGER, 8, 2);
|
|
if (!defaults)
|
|
break;
|
|
memcpy (values, defaults, 2);
|
|
meta_XFree (defaults);
|
|
break;
|
|
case G_DESKTOP_TOUCHPAD_CLICK_METHOD_NONE:
|
|
break;
|
|
case G_DESKTOP_TOUCHPAD_CLICK_METHOD_AREAS:
|
|
values[0] = 1;
|
|
break;
|
|
case G_DESKTOP_TOUCHPAD_CLICK_METHOD_FINGERS:
|
|
values[1] = 1;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
return;
|
|
}
|
|
|
|
if ((values[0] && !available[0]) || (values[1] && !available[1]))
|
|
g_warning ("Device '%s' does not support click method %d\n",
|
|
clutter_input_device_get_device_name (device), mode);
|
|
else
|
|
change_property (device, "libinput Click Method Enabled",
|
|
XA_INTEGER, 8, &values, 2);
|
|
|
|
meta_XFree(available);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_keyboard_repeat (MetaInputSettings *settings,
|
|
gboolean enabled,
|
|
guint delay,
|
|
guint interval)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
|
|
if (enabled)
|
|
{
|
|
XAutoRepeatOn (xdisplay);
|
|
XkbSetAutoRepeatRate (xdisplay, XkbUseCoreKbd, delay, interval);
|
|
}
|
|
else
|
|
{
|
|
XAutoRepeatOff (xdisplay);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
has_udev_property (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
const char *property_name)
|
|
{
|
|
#ifdef HAVE_LIBGUDEV
|
|
MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (settings);
|
|
MetaInputSettingsX11Private *priv =
|
|
meta_input_settings_x11_get_instance_private (settings_x11);
|
|
const char *device_node;
|
|
GUdevDevice *udev_device = NULL;
|
|
GUdevDevice *parent_udev_device = NULL;
|
|
|
|
device_node = clutter_input_device_get_device_node (device);
|
|
if (!device_node)
|
|
return FALSE;
|
|
|
|
udev_device = g_udev_client_query_by_device_file (priv->udev_client,
|
|
device_node);
|
|
if (!udev_device)
|
|
return FALSE;
|
|
|
|
if (NULL != g_udev_device_get_property (udev_device, property_name))
|
|
{
|
|
g_object_unref (udev_device);
|
|
return TRUE;
|
|
}
|
|
|
|
parent_udev_device = g_udev_device_get_parent (udev_device);
|
|
g_object_unref (udev_device);
|
|
|
|
if (!parent_udev_device)
|
|
return FALSE;
|
|
|
|
if (NULL != g_udev_device_get_property (parent_udev_device, property_name))
|
|
{
|
|
g_object_unref (parent_udev_device);
|
|
return TRUE;
|
|
}
|
|
|
|
g_object_unref (parent_udev_device);
|
|
return FALSE;
|
|
#else
|
|
g_warning ("Failed to set acceleration profile: no udev support");
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
static gboolean
|
|
is_mouse (MetaInputSettings *settings,
|
|
ClutterInputDevice *device)
|
|
{
|
|
return (has_udev_property (settings, device, "ID_INPUT_MOUSE") &&
|
|
!has_udev_property (settings, device, "ID_INPUT_POINTINGSTICK"));
|
|
}
|
|
|
|
static gboolean
|
|
is_trackball (MetaInputSettings *settings,
|
|
ClutterInputDevice *device)
|
|
{
|
|
return meta_input_device_is_trackball (device);
|
|
}
|
|
|
|
static void
|
|
set_device_accel_profile (ClutterInputDevice *device,
|
|
GDesktopPointerAccelProfile profile)
|
|
{
|
|
guchar *defaults, *available;
|
|
guchar values[2] = { 0 }; /* adaptive, flat */
|
|
|
|
defaults = get_property (device, "libinput Accel Profile Enabled Default",
|
|
XA_INTEGER, 8, 2);
|
|
if (!defaults)
|
|
return;
|
|
|
|
available = get_property (device, "libinput Accel Profiles Available",
|
|
XA_INTEGER, 8, 2);
|
|
if (!available)
|
|
goto err_available;
|
|
|
|
switch (profile)
|
|
{
|
|
case G_DESKTOP_POINTER_ACCEL_PROFILE_FLAT:
|
|
values[0] = 0;
|
|
values[1] = 1;
|
|
break;
|
|
case G_DESKTOP_POINTER_ACCEL_PROFILE_ADAPTIVE:
|
|
values[0] = 1;
|
|
values[1] = 0;
|
|
break;
|
|
default:
|
|
g_warn_if_reached ();
|
|
case G_DESKTOP_POINTER_ACCEL_PROFILE_DEFAULT:
|
|
values[0] = defaults[0];
|
|
values[1] = defaults[1];
|
|
break;
|
|
}
|
|
|
|
change_property (device, "libinput Accel Profile Enabled",
|
|
XA_INTEGER, 8, &values, 2);
|
|
|
|
meta_XFree (available);
|
|
|
|
err_available:
|
|
meta_XFree (defaults);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_mouse_accel_profile (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
GDesktopPointerAccelProfile profile)
|
|
{
|
|
if (!is_mouse (settings, device))
|
|
return;
|
|
|
|
set_device_accel_profile (device, profile);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_trackball_accel_profile (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
GDesktopPointerAccelProfile profile)
|
|
{
|
|
if (!is_trackball (settings, device))
|
|
return;
|
|
|
|
set_device_accel_profile (device, profile);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_tablet_mapping (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
GDesktopTabletMapping mapping)
|
|
{
|
|
MetaDisplay *display = meta_get_display ();
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
int device_id = clutter_input_device_get_device_id (device);
|
|
XDevice *xdev;
|
|
|
|
if (!display)
|
|
return;
|
|
|
|
/* Grab the puke bucket! */
|
|
meta_error_trap_push (display);
|
|
xdev = XOpenDevice (xdisplay, device_id);
|
|
if (xdev)
|
|
{
|
|
XSetDeviceMode (xdisplay, xdev,
|
|
mapping == G_DESKTOP_TABLET_MAPPING_ABSOLUTE ?
|
|
Absolute : Relative);
|
|
XCloseDevice (xdisplay, xdev);
|
|
}
|
|
|
|
if (meta_error_trap_pop_with_return (display))
|
|
{
|
|
g_warning ("Could not set tablet mapping for %s",
|
|
clutter_input_device_get_device_name (device));
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
device_query_area (ClutterInputDevice *device,
|
|
gint *width,
|
|
gint *height)
|
|
{
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
gint device_id, n_devices, i;
|
|
XIDeviceInfo *info;
|
|
Atom abs_x, abs_y;
|
|
|
|
*width = *height = 0;
|
|
device_id = clutter_input_device_get_device_id (device);
|
|
info = XIQueryDevice (xdisplay, device_id, &n_devices);
|
|
if (n_devices == 0)
|
|
return FALSE;
|
|
|
|
abs_x = XInternAtom (xdisplay, "Abs X", True);
|
|
abs_y = XInternAtom (xdisplay, "Abs Y", True);
|
|
|
|
for (i = 0; i < info->num_classes; i++)
|
|
{
|
|
XIValuatorClassInfo *valuator = (XIValuatorClassInfo *) info->classes[i];
|
|
|
|
if (valuator->type != XIValuatorClass)
|
|
continue;
|
|
if (valuator->label == abs_x)
|
|
*width = valuator->max - valuator->min;
|
|
else if (valuator->label == abs_y)
|
|
*height = valuator->max - valuator->min;
|
|
}
|
|
|
|
XIFreeDeviceInfo (info);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
update_tablet_area (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gint32 *area)
|
|
{
|
|
change_property (device, "Wacom Tablet Area",
|
|
XA_INTEGER, 32, area, 4);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_tablet_area (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
gdouble padding_left,
|
|
gdouble padding_right,
|
|
gdouble padding_top,
|
|
gdouble padding_bottom)
|
|
{
|
|
gint32 width, height, area[4] = { 0 };
|
|
|
|
if (!device_query_area (device, &width, &height))
|
|
return;
|
|
|
|
area[0] = width * padding_left;
|
|
area[1] = height * padding_top;
|
|
area[2] = width - (width * padding_right);
|
|
area[2] = height - (height * padding_bottom);
|
|
update_tablet_area (settings, device, area);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_tablet_keep_aspect (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
MetaOutput *output,
|
|
gboolean keep_aspect)
|
|
{
|
|
gint32 width, height, dev_width, dev_height, area[4] = { 0 };
|
|
|
|
if (!device_query_area (device, &dev_width, &dev_height))
|
|
return;
|
|
|
|
if (keep_aspect)
|
|
{
|
|
gdouble output_aspect, dev_aspect;
|
|
|
|
if (output && output->crtc)
|
|
{
|
|
width = output->crtc->rect.width;
|
|
height = output->crtc->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);
|
|
}
|
|
|
|
output_aspect = (gdouble) width / height;
|
|
dev_aspect = (gdouble) dev_width / dev_height;
|
|
|
|
if (dev_aspect > output_aspect)
|
|
dev_width = dev_height * output_aspect;
|
|
else if (dev_aspect < output_aspect)
|
|
dev_height = dev_width / output_aspect;
|
|
}
|
|
|
|
area[2] = dev_width;
|
|
area[3] = dev_height;
|
|
update_tablet_area (settings, device, area);
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_dispose (GObject *object)
|
|
{
|
|
#ifdef HAVE_LIBGUDEV
|
|
MetaInputSettingsX11 *settings_x11 = META_INPUT_SETTINGS_X11 (object);
|
|
MetaInputSettingsX11Private *priv =
|
|
meta_input_settings_x11_get_instance_private (settings_x11);
|
|
|
|
g_clear_object (&priv->udev_client);
|
|
#endif
|
|
|
|
G_OBJECT_CLASS (meta_input_settings_x11_parent_class)->dispose (object);
|
|
}
|
|
|
|
static guint
|
|
action_to_button (GDesktopStylusButtonAction action,
|
|
guint button)
|
|
{
|
|
switch (action)
|
|
{
|
|
case G_DESKTOP_STYLUS_BUTTON_ACTION_MIDDLE:
|
|
return CLUTTER_BUTTON_MIDDLE;
|
|
case G_DESKTOP_STYLUS_BUTTON_ACTION_RIGHT:
|
|
return CLUTTER_BUTTON_SECONDARY;
|
|
case G_DESKTOP_STYLUS_BUTTON_ACTION_BACK:
|
|
return 8;
|
|
case G_DESKTOP_STYLUS_BUTTON_ACTION_FORWARD:
|
|
return 9;
|
|
case G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT:
|
|
default:
|
|
return button;
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_stylus_button_map (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
ClutterInputDeviceTool *tool,
|
|
GDesktopStylusButtonAction primary,
|
|
GDesktopStylusButtonAction secondary)
|
|
{
|
|
MetaDisplay *display = meta_get_display ();
|
|
MetaBackend *backend = meta_get_backend ();
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
|
|
int device_id = clutter_input_device_get_device_id (device);
|
|
XDevice *xdev;
|
|
|
|
if (!display)
|
|
return;
|
|
|
|
/* Grab the puke bucket! */
|
|
meta_error_trap_push (display);
|
|
xdev = XOpenDevice (xdisplay, device_id);
|
|
if (xdev)
|
|
{
|
|
guchar map[3] = {
|
|
CLUTTER_BUTTON_PRIMARY,
|
|
action_to_button (primary, CLUTTER_BUTTON_MIDDLE),
|
|
action_to_button (secondary, CLUTTER_BUTTON_SECONDARY),
|
|
};
|
|
|
|
XSetDeviceButtonMapping (xdisplay, xdev, map, G_N_ELEMENTS (map));
|
|
XCloseDevice (xdisplay, xdev);
|
|
}
|
|
|
|
if (meta_error_trap_pop_with_return (display))
|
|
{
|
|
g_warning ("Could not set stylus button map for %s",
|
|
clutter_input_device_get_device_name (device));
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_set_stylus_pressure (MetaInputSettings *settings,
|
|
ClutterInputDevice *device,
|
|
ClutterInputDeviceTool *tool,
|
|
const gint32 pressure[4])
|
|
{
|
|
guchar values[4] = { pressure[0], pressure[1], pressure[2], pressure[3] };
|
|
|
|
change_property (device, "Wacom Pressurecurve", XA_INTEGER, 8,
|
|
&values, G_N_ELEMENTS (values));
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
MetaInputSettingsClass *input_settings_class = META_INPUT_SETTINGS_CLASS (klass);
|
|
|
|
object_class->dispose = meta_input_settings_x11_dispose;
|
|
|
|
input_settings_class->set_send_events = meta_input_settings_x11_set_send_events;
|
|
input_settings_class->set_matrix = meta_input_settings_x11_set_matrix;
|
|
input_settings_class->set_speed = meta_input_settings_x11_set_speed;
|
|
input_settings_class->set_left_handed = meta_input_settings_x11_set_left_handed;
|
|
input_settings_class->set_tap_enabled = meta_input_settings_x11_set_tap_enabled;
|
|
input_settings_class->set_invert_scroll = meta_input_settings_x11_set_invert_scroll;
|
|
input_settings_class->set_edge_scroll = meta_input_settings_x11_set_edge_scroll;
|
|
input_settings_class->set_two_finger_scroll = meta_input_settings_x11_set_two_finger_scroll;
|
|
input_settings_class->set_scroll_button = meta_input_settings_x11_set_scroll_button;
|
|
input_settings_class->set_click_method = meta_input_settings_x11_set_click_method;
|
|
input_settings_class->set_keyboard_repeat = meta_input_settings_x11_set_keyboard_repeat;
|
|
|
|
input_settings_class->set_tablet_mapping = meta_input_settings_x11_set_tablet_mapping;
|
|
input_settings_class->set_tablet_keep_aspect = meta_input_settings_x11_set_tablet_keep_aspect;
|
|
input_settings_class->set_tablet_area = meta_input_settings_x11_set_tablet_area;
|
|
|
|
input_settings_class->set_mouse_accel_profile = meta_input_settings_x11_set_mouse_accel_profile;
|
|
input_settings_class->set_trackball_accel_profile = meta_input_settings_x11_set_trackball_accel_profile;
|
|
|
|
input_settings_class->set_stylus_pressure = meta_input_settings_x11_set_stylus_pressure;
|
|
input_settings_class->set_stylus_button_map = meta_input_settings_x11_set_stylus_button_map;
|
|
|
|
input_settings_class->has_two_finger_scroll = meta_input_settings_x11_has_two_finger_scroll;
|
|
}
|
|
|
|
static void
|
|
meta_input_settings_x11_init (MetaInputSettingsX11 *settings)
|
|
{
|
|
#ifdef HAVE_LIBGUDEV
|
|
MetaInputSettingsX11Private *priv =
|
|
meta_input_settings_x11_get_instance_private (settings);
|
|
const char *subsystems[] = { NULL };
|
|
|
|
priv->udev_client = g_udev_client_new (subsystems);
|
|
#endif
|
|
}
|