Compare commits

...

69 Commits

Author SHA1 Message Date
ec5d127cd2 wayland: Emit wp_tablet_pad_group.buttons after focus changes
The buttons grabbed by the compositor might have changed in between,
so just broadcast the button array again.
2016-07-20 19:27:24 +02:00
1c1785ea6e wayland: Check serial on wp_tablet_pad.set_feedback
We must lookup the mode switch serial for the group where the button
belongs to. Also, avoid the changes if the client requests setting
the feedback for buttons owned by the compositor.
2016-07-20 19:27:24 +02:00
aef997f7a1 wayland: Export function to tell whether a button belongs to a pad group 2016-07-20 19:27:24 +02:00
27477cbd30 wayland: Check serial on wp_tablet_pad_strip.set_feedback 2016-07-20 19:27:24 +02:00
ed73efa63f wayland: Check serial on wp_tablet_pad_ring.set_feedback 2016-07-20 19:27:24 +02:00
98f26bf01a wayland: Fix label lookup on >1 strips/rings
We assumed that each group could only have 1 strip and/or ring, because
accounting is performed per group, so we could not assume the real
index for anything above 1. Get rid of this restriction, now that
MetaWaylandTabletPad does its own accounting of rings/strips, alongside
groups.
2016-07-20 19:27:24 +02:00
edda88a7dd wayland: Move strips/rings management back to MetaWaylandTabletPad
This is best for 2 reasons:
- It's feels cleaner doing first creation of rings/strips and then
  the group assignment. The other option is making groups iterate
  other all rings/strips and selectively skip those not meant for
  it, which sounds somewhat redundant.
- Some minimal accounting of rings/strips without group restrictions
  is needed for meta_wayland_tablet_pad_get_label().

The rings/strips memory is now owned by MetaWaylandTabletPad instead
of groups, which is sort of meaningless since all are meant to go
at the same time.
2016-07-20 19:27:24 +02:00
5815259897 wayland: Add method to relate a pad strip to its group 2016-07-20 19:27:24 +02:00
1f7c7bdeaa wayland: Add method to relate a pad ring to its group 2016-07-20 19:27:24 +02:00
05a5c86203 backends: Implement the "show osd" pad action
Just call back into meta_display_request_show_osd().
2016-07-20 19:27:24 +02:00
c90d7a373b core: Add special case for the pad OSD in event handling
When it's active, we want wayland to stop handling (most notably key)
events.
2016-07-20 19:27:24 +02:00
6225cc6e60 core: Add meta_display_request_pad_osd() function
There may be external/compositor-specific reasons to trigger the
pad OSD. Expose this call so the pad OSD can be triggered looking
up the right settings, monitor, etc...
2016-07-20 19:27:24 +02:00
4c4b40d468 core: Add MetaDisplay:show-pad-osd signal
This is intended to be caught in the gnome-shell code, in order to
show the OSD with the pad action mapping.
2016-07-20 19:27:24 +02:00
02ce6c5865 backends: Export function to query the mapped MetaOutput of a tablet
Or NULL if the tablet is mapped to the full desktop size.
2016-07-20 19:26:31 +02:00
522989494f backends: Export call to retrieve the base GSettings for a tablet 2016-07-20 19:26:31 +02:00
ab851fc6e5 backends: Implement "switch monitor" pad button action
This action remaps the tablet to each of the connected monitors,
or to the span of all monitors.
2016-07-20 19:26:31 +02:00
185eabd3e3 core: Add public MetaDisplay functions to get action labels for pad buttons
This API will be used from the gnome-shell pad OSD implementation, in order
to show the actions that currently apply to every button/ring/strip in the
tablet.
2016-07-20 19:26:31 +02:00
67f5b89659 backends: Add function to retrieve the label for a pad button action
As those are specified by settings.
2016-07-20 19:26:31 +02:00
c7e0b87d7e meta: Add MetaPadActionType enum
This will be used on lookups to the current action assigned to
any element in a tablet pad.
2016-07-20 19:26:31 +02:00
ec50fcd320 wayland: Add getters for the current feedback strings in MetaWaylandTabletPad
Each of the buttons/rings/strips may have one such feedback string, this API
makes is meant to make lookups consistent.
2016-07-20 19:26:31 +02:00
982802d66c wayland: Hook MetaWaylandTabletPad to pad button actions management
These are handled by the MetaInputSettings, so hook the events emitted
to it.
2016-07-20 19:26:31 +02:00
0dcca308e7 backends: Add API to trigger actions related to pad buttons
It does nothing at the moment, but can be hooked into MetaWaylandTabletPad
now. For X11, we need to trigger these for the pad events we receive from
the passive pad button grabs.
2016-07-20 19:26:31 +02:00
b68247d51e wayland: Add update() phase to MetaWaylandTabletPad
This will be needed to update internal state of pad groups.
2016-07-20 19:26:31 +02:00
499851d404 wayland: Apply pressure settings before sending wp_tablet_tool.pressure 2016-07-20 19:26:31 +02:00
ef113d708b backends: Add function to apply pressure sensitivity to tablet tools
A bezier curve is created out of the 2 control points in settings, so
the pressure is made to follow the stablished curve between 0 and 1.
2016-07-20 19:26:31 +02:00
e2b8b0bf67 wayland: Implement stylus button actions
Those just send different BTN_ keycodes.
2016-07-20 19:26:31 +02:00
ec2ab05d8e backends: Add function to retrieve the action mapped to an stylus button
This function will be useful for the wayland implementation, because buttons
are mapped at the time of sending those through the wire.
As x11/wayland implementations differ here, this function will be useful for
the wayland implementation, as the action is handled lat
2016-07-20 19:26:31 +02:00
69955471fc backends: Perform libwacom checks before applying settings
Some settings make no sense on external tablets, and others make
no sense in display/system-integrated tablets. Perform those checks
so we don't end up with possibly broken configuration.
2016-07-20 19:26:31 +02:00
e59a32afa5 backends: Disable keep-aspect and output mapping on relative devices
Those settings make no sense there, so should be made ineffective.
2016-07-20 19:26:31 +02:00
1c0b063855 backends: Implement set_tablet_mapping() in native backend
We can now just set the mapping through clutter_input_device_set_mapping()
2016-07-20 19:26:31 +02:00
0cd46afa8f clutter/evdev: Optionally report abs/rel motions for tablet tools
Depending on clutter_input_device_get_mapping(), or whether the current
tool is either cursor or lens (those don't make any sense in absolute
mode), relative motions will be reported.
2016-07-20 19:26:31 +02:00
c73cc5138b clutter: Add clutter_input_device_[gs]et_mapping()
This function call only applies to tablets, and thus will error
out unless it's called with CLUTTER_TABLET_DEVICEs. This will
allow setting absolute/relative mapping on those on the fly, as
this is optional.
2016-07-20 19:26:31 +02:00
f51972c2aa backends: Turn MetaInputSettings into a singleton
We will need to fetch information from it at certain places.
The MetaBackend still takes care of freeing it though.
2016-07-20 19:26:31 +02:00
f81e0f8922 backends: Fetch libwacom information for tablets in MetaInputSettings
Given that information defines largely how such devices are to be
configured, it makes sense to have that information at hand. A getter
has been also added for the places where it could be useful, although
it will require HAVE_LIBWACOM checks in callers too.
2016-07-20 19:26:31 +02:00
1bf263f038 wayland: Implement wp_tablet.path
Now that we have clutter_input_device_get_device_node(), it is trivial
to implement.
2016-07-20 19:26:31 +02:00
257b16680f clutter/x11: Set device node information in XI2 devices 2016-07-20 19:26:31 +02:00
ed6eb8c94b clutter/evdev: Set device node information to evdev devices 2016-07-20 19:26:31 +02:00
95181bdbaa clutter: Add clutter_input_device_get_device_node()
This function is meant to return the device node path (eg. /dev/input/...),
which will be useful to wire up a few things.
2016-07-20 19:26:31 +02:00
59be5bf3b1 backends: Add function to lookup the mapping for a given tablet
At least for wayland, this needs implementing within mutter. So add
a function to look this setting up.
2016-07-20 19:26:31 +02:00
7f8932b489 backends: Store mappable devices' info in the hashtable
Instead of as closure data. We will need to store (and query) more
per-device info, so access to this struct is necessary.
2016-07-20 19:26:31 +02:00
f2feb6d53d backends: Map tablets/pads, and wire to configuration vfuncs
With this, the left-handed setting works. The other configuration
vfuncs remain empty stubs, but will be correctly applied when those
are handled.
2016-07-20 19:26:31 +02:00
47067e6d17 backends: Add empty stubs for tablet configuration
Those will be called when configuring tablets.
2016-07-20 19:26:31 +02:00
3386e5dc39 wayland: Implement wp_tablet_tool.hardware_id_wacom
We can now fetch this info from the ClutterInputDeviceTool, so
use it to implement this event.
2016-07-20 19:26:31 +02:00
384400cd24 clutter/evdev: Set tool IDs 2016-07-20 19:26:31 +02:00
be9997c717 clutter: Add ClutterInputDeviceTool:id property 2016-07-20 19:26:31 +02:00
d3be071196 configure: Check for libwacom
It will be used for some advanced tablet features, which we can't
get solely from libinput.
2016-07-20 19:26:31 +02:00
de704e591b wayland: Add focus management to pads
All pads will share the same focus than the keyboard, so this means that:
- The focus changes in-sync for keyboard and all pad devices, and
- Newly plugged pads will be immediately focused on that same surface
2016-07-20 19:26:31 +02:00
a14f0edcae wayland: Add MetaWaylandTabletSeat API to correlate pads/tablets
All pads have one tablet, but a tablet may have multiple pads. Add
API to look things up from a MetaWaylandTablet(Pad).
2016-07-20 19:26:31 +02:00
bf5324a339 wayland: Add pointer from MetaWaylandTabletSeat to MetaWaylandSeat
It will be useful to backreference to the MetaWaylandSeat from tablet
code.
2016-07-20 19:26:31 +02:00
9855ff010a wayland: Wire up pad device event management
The tablet manager will now lookup the correct MetaWaylandTabletSeat,
and forward the events through it.
2016-07-20 19:26:31 +02:00
6bd06cf40b wayland: Implement pad management in MetaWaylandTabletSeat
Now pads are looked up and notified upon, both on startup and
when plugging a tablet.
2016-07-20 19:26:31 +02:00
01fd218e17 wayland: Implement wp_tablet_pad
This object represents the collection of buttons, strips and rings
in a tablet pad. All the objects created (pad, strips and rings)
share a common focus surface and have the same lifetime.
2016-07-20 19:26:31 +02:00
f8c0301ecc wayland: Implement wp_tablet_pad_group 2016-07-20 19:26:31 +02:00
2354643d55 wayland: Implement wp_tablet_pad_strip
This represents pad sliders.
2016-07-20 19:26:31 +02:00
c1d1477c64 wayland: Implement wp_tablet_pad_ring
This object represents pad "wheels"
2016-07-20 19:26:31 +02:00
04629d2bc2 clutter: Handle pad button events in clutter_event_get_button() 2016-07-20 19:26:31 +02:00
c789459a31 clutter/evdev: Translate/emit libinput pad events 2016-07-20 19:26:31 +02:00
2f7602f297 clutter/evdev: Handle management of pad devices 2016-07-20 19:26:31 +02:00
d5459427d5 clutter: Add ::n-rings and ::n-strips property to ClutterInputDevice
This will only be practical for pads (and maybe generic buttonsets in
the future?), we just need to know the number as the events will also
contain a number as the identificator.
2016-07-20 19:26:31 +02:00
379c6fb81a clutter: Add pad event types
And their management along the pipeline.
2016-07-20 19:26:31 +02:00
fc5af32cdc clutter: Add clutter_event_get_mode_group()
This event can be used on pad events to find out the group they
pertain to.
2016-07-20 19:26:31 +02:00
b71d7058db clutter: Add pad event structs
Those map closely what we get from libinput. Button events have
been made its own separate struct, its semantics fall somewhere
in between of ClutterButtonEvent and ClutterKeyEvent, so is better
emitted as its own set.
2016-07-20 19:26:31 +02:00
1d9d176c3f clutter: Add "pad" device type 2016-07-20 19:26:31 +02:00
cd911584eb wayland: Set an specific role on surfaces passed in wp_tablet_tool.set_cursor
This is now separated from the generic cursor one. This means that wl_surfaces
can't be shared across wl_pointer and wp_tablet_tool. This is a change in
tablet protocol v2.
2016-07-20 19:26:31 +02:00
2ff629a984 wayland: Add MetaWaylandSurfaceRoleTabletCursor
This is a simple subclass of MetaWaylandSurfaceRoleCursor, mostly
so we can distinguish by GType, the methods in the parent class
still apply and are useful.
2016-07-20 19:26:31 +02:00
b0a3c472ea wayland: Make MetaWaylandSurfaceRoleCursor derivable 2016-07-20 19:26:31 +02:00
7ecbca6291 wayland: Make additional data in MetaWaylandSurfaceRoleCursor private
This will help subclassing it.
2016-07-20 19:26:31 +02:00
780c66fa73 wayland: Use wl_fixed_t for angle arguments in wp_tablet_tool
This is a change in tablet protocol v2
2016-07-20 19:26:31 +02:00
ffa991d422 wayland: Use tablet protocol v2
This commit merely updates the code generation from the v2 protocol
description.
2016-07-20 19:26:31 +02:00
43 changed files with 4051 additions and 207 deletions

View File

@ -131,9 +131,16 @@ struct _ClutterInputDevice
gchar *vendor_id;
gchar *product_id;
gchar *node_path;
GPtrArray *tools;
gint n_rings;
gint n_strips;
gint n_mode_groups;
ClutterInputDeviceMapping mapping_mode;
guint has_cursor : 1;
guint is_enabled : 1;
};

View File

@ -794,6 +794,10 @@ typedef enum { /*< prefix=CLUTTER >*/
CLUTTER_TOUCHPAD_SWIPE,
CLUTTER_PROXIMITY_IN,
CLUTTER_PROXIMITY_OUT,
CLUTTER_PAD_BUTTON_PRESS,
CLUTTER_PAD_BUTTON_RELEASE,
CLUTTER_PAD_STRIP,
CLUTTER_PAD_RING,
CLUTTER_EVENT_LAST /* helper */
} ClutterEventType;
@ -900,6 +904,7 @@ typedef enum { /*< prefix=CLUTTER_FLOW >*/
* @CLUTTER_PEN_DEVICE: A pen device
* @CLUTTER_ERASER_DEVICE: An eraser device
* @CLUTTER_CURSOR_DEVICE: A cursor device
* @CLUTTER_PAD_DEVICE: A tablet pad
* @CLUTTER_N_DEVICE_TYPES: The number of device types
*
* The types of input devices available.
@ -920,6 +925,7 @@ typedef enum {
CLUTTER_PEN_DEVICE,
CLUTTER_ERASER_DEVICE,
CLUTTER_CURSOR_DEVICE,
CLUTTER_PAD_DEVICE,
CLUTTER_N_DEVICE_TYPES
} ClutterInputDeviceType;
@ -1520,6 +1526,16 @@ typedef enum {
CLUTTER_INPUT_DEVICE_TOOL_LENS
} ClutterInputDeviceToolType;
typedef enum {
CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN,
CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER,
} ClutterInputDevicePadSource;
typedef enum {
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE,
} ClutterInputDeviceMapping;
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */

View File

@ -413,6 +413,10 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
clutter_point_init (position, 0.f, 0.f);
break;
@ -483,6 +487,10 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
break;
case CLUTTER_ENTER:
@ -811,9 +819,15 @@ clutter_event_get_button (const ClutterEvent *event)
{
g_return_val_if_fail (event != NULL, 0);
g_return_val_if_fail (event->type == CLUTTER_BUTTON_PRESS ||
event->type == CLUTTER_BUTTON_RELEASE, 0);
event->type == CLUTTER_BUTTON_RELEASE ||
event->type == CLUTTER_PAD_BUTTON_PRESS ||
event->type == CLUTTER_PAD_BUTTON_RELEASE, 0);
return event->button.button;
if (event->type == CLUTTER_BUTTON_PRESS ||
event->type == CLUTTER_BUTTON_RELEASE)
return event->button.button;
else
return event->pad_button.button;
}
/**
@ -1133,6 +1147,19 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_PROXIMITY_OUT:
event->proximity.device = device;
break;
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
event->pad_button.device = device;
break;
case CLUTTER_PAD_STRIP:
event->pad_strip.device = device;
break;
case CLUTTER_PAD_RING:
event->pad_ring.device = device;
break;
}
}
@ -1217,6 +1244,19 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_PROXIMITY_OUT:
device = event->proximity.device;
break;
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
device = event->pad_button.device;
break;
case CLUTTER_PAD_STRIP:
device = event->pad_strip.device;
break;
case CLUTTER_PAD_RING:
device = event->pad_ring.device;
break;
}
return device;
@ -1708,6 +1748,10 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
break;
}
@ -2108,3 +2152,24 @@ clutter_event_get_scroll_finish_flags (const ClutterEvent *event)
return event->scroll.finish_flags;
}
guint
clutter_event_get_mode_group (const ClutterEvent *event)
{
g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS ||
event->type == CLUTTER_PAD_BUTTON_RELEASE ||
event->type == CLUTTER_PAD_RING ||
event->type == CLUTTER_PAD_STRIP, 0);
switch (event->type)
{
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
return event->pad_button.group;
case CLUTTER_PAD_RING:
return event->pad_ring.group;
case CLUTTER_PAD_STRIP:
return event->pad_strip.group;
default:
return 0;
}
}

View File

@ -118,6 +118,9 @@ typedef struct _ClutterTouchEvent ClutterTouchEvent;
typedef struct _ClutterTouchpadPinchEvent ClutterTouchpadPinchEvent;
typedef struct _ClutterTouchpadSwipeEvent ClutterTouchpadSwipeEvent;
typedef struct _ClutterProximityEvent ClutterProximityEvent;
typedef struct _ClutterPadButtonEvent ClutterPadButtonEvent;
typedef struct _ClutterPadStripEvent ClutterPadStripEvent;
typedef struct _ClutterPadRingEvent ClutterPadRingEvent;
/**
* ClutterAnyEvent:
@ -493,6 +496,49 @@ struct _ClutterTouchpadSwipeEvent
gfloat dy;
};
struct _ClutterPadButtonEvent
{
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
guint32 button;
guint32 group;
ClutterInputDevice *device;
};
struct _ClutterPadStripEvent
{
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
ClutterInputDevice *device;
ClutterInputDevicePadSource strip_source;
guint32 strip_number;
guint32 group;
gdouble value;
};
struct _ClutterPadRingEvent
{
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
ClutterInputDevice *device;
ClutterInputDevicePadSource ring_source;
guint32 ring_number;
guint32 group;
gdouble angle;
};
/**
* ClutterEvent:
*
@ -516,6 +562,9 @@ union _ClutterEvent
ClutterTouchpadPinchEvent touchpad_pinch;
ClutterTouchpadSwipeEvent touchpad_swipe;
ClutterProximityEvent proximity;
ClutterPadButtonEvent pad_button;
ClutterPadStripEvent pad_strip;
ClutterPadRingEvent pad_ring;
};
/**
@ -722,6 +771,10 @@ void clutter_event_get_gesture_motion_delta (const Clut
ClutterScrollSource clutter_event_get_scroll_source (const ClutterEvent *event);
ClutterScrollFinishFlags clutter_event_get_scroll_finish_flags (const ClutterEvent *event);
CLUTTER_AVAILABLE_IN_ALL
guint clutter_event_get_mode_group (const ClutterEvent *event);
G_END_DECLS
#endif /* __CLUTTER_EVENT_H__ */

View File

@ -34,12 +34,14 @@ struct _ClutterInputDeviceToolPrivate
{
ClutterInputDeviceToolType type;
guint64 serial;
guint64 id;
};
enum {
PROP_0,
PROP_TYPE,
PROP_SERIAL,
PROP_ID,
PROP_LAST
};
@ -66,6 +68,9 @@ clutter_input_device_tool_set_property (GObject *object,
case PROP_SERIAL:
priv->serial = g_value_get_uint64 (value);
break;
case PROP_ID:
priv->id = g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -90,6 +95,9 @@ clutter_input_device_tool_get_property (GObject *object,
case PROP_SERIAL:
g_value_set_uint64 (value, priv->serial);
break;
case PROP_ID:
g_value_set_uint64 (value, priv->id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -116,6 +124,12 @@ clutter_input_device_tool_class_init (ClutterInputDeviceToolClass *klass)
P_("Tool serial"),
0, G_MAXUINT64, 0,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
props[PROP_ID] =
g_param_spec_uint64 ("id",
P_("Tool ID"),
P_("Tool ID"),
0, G_MAXUINT64, 0,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, PROP_LAST, props);
}
@ -136,7 +150,7 @@ clutter_input_device_tool_init (ClutterInputDeviceTool *tool)
*
* Since: 1.28
**/
guint
guint64
clutter_input_device_tool_get_serial (ClutterInputDeviceTool *tool)
{
ClutterInputDeviceToolPrivate *priv;
@ -170,3 +184,24 @@ clutter_input_device_tool_get_tool_type (ClutterInputDeviceTool *tool)
return priv->type;
}
/**
* clutter_input_device_tool_get_id:
* @tool: a #ClutterInputDeviceTool
*
* Gets the ID of this tool, this value can be used to identify a
* physical tool (eg. a tablet pen) across program executions.
*
* Returns: The tool ID for this tool
**/
guint64
clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool)
{
ClutterInputDeviceToolPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), 0);
priv = clutter_input_device_tool_get_instance_private (tool);
return priv->id;
}

View File

@ -56,11 +56,14 @@ CLUTTER_AVAILABLE_IN_ALL
GType clutter_input_device_tool_get_type (void) G_GNUC_CONST;
CLUTTER_AVAILABLE_IN_ALL
guint clutter_input_device_tool_get_serial (ClutterInputDeviceTool *tool);
guint64 clutter_input_device_tool_get_serial (ClutterInputDeviceTool *tool);
CLUTTER_AVAILABLE_IN_ALL
ClutterInputDeviceToolType clutter_input_device_tool_get_tool_type (ClutterInputDeviceTool *tool);
CLUTTER_AVAILABLE_IN_ALL
guint64 clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_TOOL_H__ */

View File

@ -70,6 +70,12 @@ enum
PROP_VENDOR_ID,
PROP_PRODUCT_ID,
PROP_N_STRIPS,
PROP_N_RINGS,
PROP_N_MODE_GROUPS,
PROP_DEVICE_NODE,
PROP_MAPPING_MODE,
PROP_LAST
};
@ -195,6 +201,26 @@ clutter_input_device_set_property (GObject *gobject,
self->product_id = g_value_dup_string (value);
break;
case PROP_N_RINGS:
self->n_rings = g_value_get_int (value);
break;
case PROP_N_STRIPS:
self->n_strips = g_value_get_int (value);
break;
case PROP_N_MODE_GROUPS:
self->n_mode_groups = g_value_get_int (value);
break;
case PROP_DEVICE_NODE:
self->node_path = g_value_dup_string (value);
break;
case PROP_MAPPING_MODE:
self->mapping_mode = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -255,6 +281,26 @@ clutter_input_device_get_property (GObject *gobject,
g_value_set_string (value, self->product_id);
break;
case PROP_N_RINGS:
g_value_set_int (value, self->n_rings);
break;
case PROP_N_STRIPS:
g_value_set_int (value, self->n_strips);
break;
case PROP_N_MODE_GROUPS:
g_value_set_int (value, self->n_mode_groups);
break;
case PROP_DEVICE_NODE:
g_value_set_string (value, self->node_path);
break;
case PROP_MAPPING_MODE:
g_value_set_enum (value, self->mapping_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -432,6 +478,42 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
NULL,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_N_RINGS] =
g_param_spec_int ("n-rings",
P_("Number of rings"),
P_("Number of rings (circular sliders) in this device"),
0, G_MAXINT, 0,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_N_STRIPS] =
g_param_spec_int ("n-strips",
P_("Number of strips"),
P_("Number of strips (linear sliders) in this device"),
0, G_MAXINT, 0,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_N_MODE_GROUPS] =
g_param_spec_int ("n-mode-groups",
P_("Number of mode groups"),
P_("Number of mode groups"),
0, G_MAXINT, 0,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_DEVICE_NODE] =
g_param_spec_string ("device-node",
P_("Device node path"),
P_("Device node path"),
NULL,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_MAPPING_MODE] =
g_param_spec_enum ("mapping-mode",
P_("Device mapping mode"),
P_("Device mapping mode"),
CLUTTER_TYPE_INPUT_DEVICE_MAPPING,
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
CLUTTER_PARAM_READWRITE);
gobject_class->dispose = clutter_input_device_dispose;
gobject_class->set_property = clutter_input_device_set_property;
gobject_class->get_property = clutter_input_device_get_property;
@ -2066,3 +2148,64 @@ clutter_input_device_update_from_tool (ClutterInputDevice *device,
if (device_class->update_from_tool)
device_class->update_from_tool (device, tool);
}
gint
clutter_input_device_get_n_rings (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
return device->n_rings;
}
gint
clutter_input_device_get_n_strips (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
return device->n_strips;
}
gint
clutter_input_device_get_n_mode_groups (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
g_return_val_if_fail (clutter_input_device_get_device_type (device) ==
CLUTTER_PAD_DEVICE, 0);
return device->n_mode_groups;
}
const gchar *
clutter_input_device_get_device_node (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
return device->node_path;
}
ClutterInputDeviceMapping
clutter_input_device_get_mapping_mode (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
g_return_val_if_fail (clutter_input_device_get_device_type (device) ==
CLUTTER_TABLET_DEVICE,
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
return device->mapping_mode;
}
void
clutter_input_device_set_mapping_mode (ClutterInputDevice *device,
ClutterInputDeviceMapping mapping)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
g_return_if_fail (clutter_input_device_get_device_type (device) ==
CLUTTER_TABLET_DEVICE);
if (device->mapping_mode == mapping)
return;
device->mapping_mode = mapping;
g_object_notify (G_OBJECT (device), "mapping-mode");
}

View File

@ -140,6 +140,23 @@ const gchar * clutter_input_device_get_vendor_id (ClutterInputDev
CLUTTER_AVAILABLE_IN_1_22
const gchar * clutter_input_device_get_product_id (ClutterInputDevice *device);
CLUTTER_AVAILABLE_IN_ALL
gint clutter_input_device_get_n_rings (ClutterInputDevice *device);
CLUTTER_AVAILABLE_IN_ALL
gint clutter_input_device_get_n_strips (ClutterInputDevice *device);
CLUTTER_AVAILABLE_IN_ALL
gint clutter_input_device_get_n_mode_groups (ClutterInputDevice *device);
CLUTTER_AVAILABLE_IN_ALL
const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device);
CLUTTER_AVAILABLE_IN_ALL
ClutterInputDeviceMapping clutter_input_device_get_mapping_mode (ClutterInputDevice *device);
CLUTTER_AVAILABLE_IN_ALL
void clutter_input_device_set_mapping_mode (ClutterInputDevice *device,
ClutterInputDeviceMapping mapping);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_H__ */

View File

@ -2163,6 +2163,10 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
{
ClutterActor *actor = NULL;

View File

@ -183,6 +183,7 @@ static const char *device_type_str[] = {
"pen", /* CLUTTER_PEN_DEVICE */
"eraser", /* CLUTTER_ERASER_DEVICE */
"cursor", /* CLUTTER_CURSOR_DEVICE */
"pad", /* CLUTTER_PAD_DEVICE */
};
#endif /* CLUTTER_ENABLE_DEBUG */
@ -549,6 +550,24 @@ notify_relative_motion (ClutterInputDevice *input_device,
queue_event (event);
}
static void
notify_relative_tool_motion (ClutterInputDevice *input_device,
guint64 time_us,
gfloat dx,
gfloat dy,
gdouble *axes)
{
ClutterEvent *event;
gfloat x, y;
x = input_device->current_x + dx;
y = input_device->current_y + dy;
event = new_absolute_motion_event (input_device, time_us, x, y, axes);
_clutter_evdev_event_set_relative_motion (event, dx, dy, 0, 0);
queue_event (event);
}
static ClutterScrollDirection
discrete_to_direction (gdouble discrete_x,
gdouble discrete_y)
@ -949,6 +968,133 @@ notify_proximity (ClutterInputDevice *input_device,
queue_event (event);
}
static void
notify_pad_button (ClutterInputDevice *input_device,
guint64 time_us,
guint32 button,
guint32 mode_group,
guint32 pressed)
{
ClutterInputDeviceEvdev *device_evdev;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterEvent *event;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
if (pressed)
event = clutter_event_new (CLUTTER_PAD_BUTTON_PRESS);
else
event = clutter_event_new (CLUTTER_PAD_BUTTON_RELEASE);
device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
seat = _clutter_input_device_evdev_get_seat (device_evdev);
_clutter_evdev_event_set_time_usec (event, time_us);
event->pad_button.stage = stage;
event->pad_button.button = button;
event->pad_button.group = mode_group;
clutter_event_set_device (event, input_device);
clutter_event_set_source_device (event, input_device);
clutter_event_set_time (event, us2ms (time_us));
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
}
static void
notify_pad_strip (ClutterInputDevice *input_device,
guint64 time_us,
guint32 strip_number,
guint32 strip_source,
guint32 mode_group,
gdouble value)
{
ClutterInputDeviceEvdev *device_evdev;
ClutterInputDevicePadSource source;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterEvent *event;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
if (strip_source == LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER)
source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER;
else
source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN;
device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
seat = _clutter_input_device_evdev_get_seat (device_evdev);
event = clutter_event_new (CLUTTER_PAD_STRIP);
_clutter_evdev_event_set_time_usec (event, time_us);
event->pad_strip.strip_source = source;
event->pad_strip.stage = stage;
event->pad_strip.strip_number = strip_number;
event->pad_strip.value = value;
event->pad_strip.group = mode_group;
clutter_event_set_device (event, input_device);
clutter_event_set_source_device (event, input_device);
clutter_event_set_time (event, us2ms (time_us));
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
}
static void
notify_pad_ring (ClutterInputDevice *input_device,
guint64 time_us,
guint32 ring_number,
guint32 ring_source,
guint32 mode_group,
gdouble angle)
{
ClutterInputDeviceEvdev *device_evdev;
ClutterInputDevicePadSource source;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterEvent *event;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
if (ring_source == LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER)
source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER;
else
source = CLUTTER_INPUT_DEVICE_PAD_SOURCE_UNKNOWN;
device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
seat = _clutter_input_device_evdev_get_seat (device_evdev);
event = clutter_event_new (CLUTTER_PAD_RING);
_clutter_evdev_event_set_time_usec (event, time_us);
event->pad_ring.ring_source = source;
event->pad_ring.stage = stage;
event->pad_ring.ring_number = ring_number;
event->pad_ring.angle = angle;
event->pad_ring.group = mode_group;
clutter_event_set_device (event, input_device);
clutter_event_set_source_device (event, input_device);
clutter_event_set_time (event, us2ms (time_us));
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
}
static void
dispatch_libinput (ClutterDeviceManagerEvdev *manager_evdev)
{
@ -2009,12 +2155,15 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
{
guint64 time;
double x, y, *axes;
double x, y, dx, dy, *axes;
gfloat stage_width, stage_height;
ClutterStage *stage;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
ClutterInputDeviceEvdev *evdev_device;
device = libinput_device_get_user_data (libinput_device);
evdev_device = CLUTTER_INPUT_DEVICE_EVDEV (device);
stage = _clutter_input_device_get_stage (device);
if (!stage)
@ -2028,10 +2177,22 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage));
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
x = libinput_event_tablet_tool_get_x_transformed (tablet_event, stage_width);
y = libinput_event_tablet_tool_get_y_transformed (tablet_event, stage_height);
notify_absolute_motion (device, time, x, y, axes);
if (clutter_input_device_get_mapping_mode (device) == CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE ||
clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_MOUSE ||
clutter_input_device_tool_get_tool_type (evdev_device->last_tool) == CLUTTER_INPUT_DEVICE_TOOL_LENS)
{
dx = libinput_event_tablet_tool_get_dx (tablet_event);
dy = libinput_event_tablet_tool_get_dy (tablet_event);
notify_relative_tool_motion (device, time, dx, dy, axes);
}
else
{
x = libinput_event_tablet_tool_get_x_transformed (tablet_event, stage_width);
y = libinput_event_tablet_tool_get_y_transformed (tablet_event, stage_height);
notify_absolute_motion (device, time, x, y, axes);
}
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
@ -2084,6 +2245,68 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
notify_button (device, time, BTN_TOUCH, button_state);
break;
}
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
{
guint64 time;
guint32 button_state, button, group;
struct libinput_tablet_pad_mode_group *mode_group;
struct libinput_event_tablet_pad *pad_event =
libinput_event_get_tablet_pad_event (event);
device = libinput_device_get_user_data (libinput_device);
time = libinput_event_tablet_pad_get_time_usec (pad_event);
mode_group = libinput_event_tablet_pad_get_mode_group (pad_event);
group = libinput_tablet_pad_mode_group_get_index (mode_group);
button = libinput_event_tablet_pad_get_button_number (pad_event);
button_state = libinput_event_tablet_pad_get_button_state (pad_event) ==
LIBINPUT_BUTTON_STATE_PRESSED;
notify_pad_button (device, time, button, group, button_state);
break;
}
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
{
guint64 time;
guint32 number, source, group;
struct libinput_tablet_pad_mode_group *mode_group;
struct libinput_event_tablet_pad *pad_event =
libinput_event_get_tablet_pad_event (event);
gdouble value;
device = libinput_device_get_user_data (libinput_device);
time = libinput_event_tablet_pad_get_time_usec (pad_event);
number = libinput_event_tablet_pad_get_strip_number (pad_event);
value = libinput_event_tablet_pad_get_strip_position (pad_event);
source = libinput_event_tablet_pad_get_strip_source (pad_event);
mode_group = libinput_event_tablet_pad_get_mode_group (pad_event);
group = libinput_tablet_pad_mode_group_get_index (mode_group);
notify_pad_strip (device, time, number, source, group, value);
break;
}
case LIBINPUT_EVENT_TABLET_PAD_RING:
{
guint64 time;
guint32 number, source, group;
struct libinput_tablet_pad_mode_group *mode_group;
struct libinput_event_tablet_pad *pad_event =
libinput_event_get_tablet_pad_event (event);
gdouble angle;
device = libinput_device_get_user_data (libinput_device);
time = libinput_event_tablet_pad_get_time_usec (pad_event);
number = libinput_event_tablet_pad_get_ring_number (pad_event);
angle = libinput_event_tablet_pad_get_ring_position (pad_event);
source = libinput_event_tablet_pad_get_ring_source (pad_event);
mode_group = libinput_event_tablet_pad_get_mode_group (pad_event);
group = libinput_tablet_pad_mode_group_get_index (mode_group);
notify_pad_ring (device, time, number, source, group, angle);
break;
}
default:
handled = FALSE;
}

View File

@ -141,13 +141,24 @@ _clutter_input_device_evdev_new (ClutterDeviceManager *manager,
ClutterInputDeviceType type;
ClutterDeviceManagerEvdev *manager_evdev;
gchar *vendor, *product;
gint device_id;
gint device_id, n_rings = 0, n_strips = 0, n_groups = 1;
gchar *node_path;
type = _clutter_input_device_evdev_determine_type (libinput_device);
vendor = g_strdup_printf ("%.4x", libinput_device_get_id_vendor (libinput_device));
product = g_strdup_printf ("%.4x", libinput_device_get_id_product (libinput_device));
manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (manager);
device_id = _clutter_device_manager_evdev_acquire_device_id (manager_evdev);
node_path = g_strdup_printf ("/dev/input/%s", libinput_device_get_sysname (libinput_device));
if (libinput_device_has_capability (libinput_device,
LIBINPUT_DEVICE_CAP_TABLET_PAD))
{
n_rings = libinput_device_tablet_pad_get_num_rings (libinput_device);
n_strips = libinput_device_tablet_pad_get_num_strips (libinput_device);
n_groups = libinput_device_tablet_pad_get_num_mode_groups (libinput_device);
}
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_EVDEV,
"id", device_id,
"name", libinput_device_get_name (libinput_device),
@ -157,6 +168,10 @@ _clutter_input_device_evdev_new (ClutterDeviceManager *manager,
"enabled", TRUE,
"vendor-id", vendor,
"product-id", product,
"n-rings", n_rings,
"n-strips", n_strips,
"n-mode-groups", n_groups,
"device-node", node_path,
NULL);
device->seat = seat;
@ -243,6 +258,8 @@ _clutter_input_device_evdev_determine_type (struct libinput_device *ldev)
return CLUTTER_TOUCHPAD_DEVICE;
else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_TABLET_TOOL))
return CLUTTER_TABLET_DEVICE;
else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_TABLET_PAD))
return CLUTTER_PAD_DEVICE;
else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_POINTER))
return CLUTTER_POINTER_DEVICE;
else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_TOUCH))

View File

@ -63,6 +63,7 @@ clutter_input_device_tool_evdev_new (struct libinput_tablet_tool *tool,
evdev_tool = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV,
"type", type,
"serial", serial,
"id", libinput_tablet_tool_get_tool_id (tool),
NULL);
evdev_tool->tool = libinput_tablet_tool_ref (tool);

View File

@ -321,6 +321,42 @@ get_device_ids (ClutterBackendX11 *backend_x11,
return TRUE;
}
static gchar *
get_device_node_path (ClutterBackendX11 *backend_x11,
XIDeviceInfo *info)
{
gulong nitems, bytes_after;
guchar *data;
int rc, format;
Atom prop, type;
gchar *node_path;
prop = XInternAtom (backend_x11->xdpy, "Device Node", False);
if (prop == None)
return NULL;
clutter_x11_trap_x_errors ();
rc = XIGetProperty (backend_x11->xdpy,
info->deviceid, prop, 0, 1024, False,
XA_STRING, &type, &format, &nitems, &bytes_after,
(guchar **) &data);
if (clutter_x11_untrap_x_errors ())
return NULL;
if (rc != Success || type != XA_STRING || format != 8)
{
XFree (data);
return FALSE;
}
node_path = g_strdup ((char *) data);
XFree (data);
return node_path;
}
static ClutterInputDevice *
create_device (ClutterDeviceManagerXI2 *manager_xi2,
ClutterBackendX11 *backend_x11,
@ -331,7 +367,7 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
ClutterInputMode mode;
gboolean is_enabled;
guint num_touches = 0;
gchar *vendor_id = NULL, *product_id = NULL;
gchar *vendor_id = NULL, *product_id = NULL, *node_path = NULL;
if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard)
{
@ -391,7 +427,10 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
if (info->use != XIMasterKeyboard &&
info->use != XIMasterPointer)
get_device_ids (backend_x11, info, &vendor_id, &product_id);
{
get_device_ids (backend_x11, info, &vendor_id, &product_id);
node_path = get_device_node_path (backend_x11, info);
}
retval = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_XI2,
"name", info->name,
@ -404,6 +443,7 @@ create_device (ClutterDeviceManagerXI2 *manager_xi2,
"enabled", is_enabled,
"vendor-id", vendor_id,
"product-id", product_id,
"device-node", node_path,
NULL);
translate_device_classes (backend_x11->xdpy, retval,

View File

@ -59,6 +59,8 @@ AM_PATH_GLIB_2_0([2.49.0])
CANBERRA_GTK=libcanberra-gtk3
CANBERRA_GTK_VERSION=0.26
LIBWACOM_VERSION=0.19
MUTTER_PC_MODULES="
gtk+-3.0 >= 3.19.8
gio-unix-2.0 >= 2.35.1
@ -109,6 +111,11 @@ AC_ARG_WITH(libcanberra,
[disable the use of libcanberra for playing sounds]),,
with_libcanberra=auto)
AC_ARG_WITH(libwacom,
AC_HELP_STRING([--without-libwacom],
[disable the use of libwacom for advanced tablet management]),,
with_libwacom=auto)
AC_ARG_WITH([xwayland-path],
[AS_HELP_STRING([--with-xwayland-path], [Absolute path for an X Wayland server])],
[XWAYLAND_PATH="$withval"],
@ -170,6 +177,24 @@ else
fi
fi
have_libwacom=no
AC_MSG_CHECKING([libwacom])
if test x$with_libwacom = xno ; then
AC_MSG_RESULT([disabled])
else
if $PKG_CONFIG --exists libwacom '>=' $LIBWACOM_VERSION; then
have_libwacom=yes
AC_MSG_RESULT(yes)
MUTTER_PC_MODULES="$MUTTER_PC_MODULES libwacom"
AC_DEFINE([HAVE_LIBWACOM], 1, [Building with libwacom for advanced tablet management])
else
AC_MSG_RESULT(no)
if test x$with_libwacom = xyes ; then
AC_MSG_ERROR([libwacom forced but not found])
fi
fi
fi
INTROSPECTION_VERSION=0.9.5
GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_VERSION])
@ -423,6 +448,7 @@ mutter-$VERSION
Startup notification: ${have_startup_notification}
libcanberra: ${have_libcanberra}
libwacom: ${have_libwacom}
Introspection: ${found_introspection}
Session management: ${found_sm}
Wayland: ${have_wayland}

View File

@ -67,8 +67,8 @@ mutter_built_sources += \
relative-pointer-unstable-v1-server-protocol.h \
pointer-constraints-unstable-v1-protocol.c \
pointer-constraints-unstable-v1-server-protocol.h \
tablet-unstable-v1-protocol.c \
tablet-unstable-v1-server-protocol.h \
tablet-unstable-v2-protocol.c \
tablet-unstable-v2-server-protocol.h \
$(NULL)
endif
@ -317,12 +317,22 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-tablet-seat.h \
wayland/meta-wayland-tablet-tool.c \
wayland/meta-wayland-tablet-tool.h \
wayland/meta-wayland-tablet-pad.c \
wayland/meta-wayland-tablet-pad.h \
wayland/meta-wayland-tablet-pad-group.c \
wayland/meta-wayland-tablet-pad-group.h \
wayland/meta-wayland-tablet-pad-ring.c \
wayland/meta-wayland-tablet-pad-ring.h \
wayland/meta-wayland-tablet-pad-strip.c \
wayland/meta-wayland-tablet-pad-strip.h \
wayland/meta-wayland-touch.c \
wayland/meta-wayland-touch.h \
wayland/meta-wayland-surface.c \
wayland/meta-wayland-surface.h \
wayland/meta-wayland-surface-role-cursor.c \
wayland/meta-wayland-surface-role-cursor.h \
wayland/meta-wayland-surface-role-tablet-cursor.c \
wayland/meta-wayland-surface-role-tablet-cursor.h \
wayland/meta-wayland-types.h \
wayland/meta-wayland-versions.h \
wayland/meta-wayland-outputs.c \

View File

@ -316,7 +316,7 @@ meta_backend_real_post_init (MetaBackend *backend)
g_slist_free (devices);
}
priv->input_settings = meta_input_settings_create ();
priv->input_settings = meta_input_settings_get ();
center_pointer (backend);
}

View File

@ -23,9 +23,14 @@
#define META_INPUT_SETTINGS_PRIVATE_H
#include "display-private.h"
#include "meta-monitor-manager-private.h"
#include <clutter/clutter.h>
#ifdef HAVE_LIBWACOM
#include <libwacom/libwacom.h>
#endif
#define META_TYPE_INPUT_SETTINGS (meta_input_settings_get_type ())
#define META_INPUT_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_INPUT_SETTINGS, MetaInputSettings))
#define META_INPUT_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_INPUT_SETTINGS, MetaInputSettingsClass))
@ -78,10 +83,58 @@ struct _MetaInputSettingsClass
gboolean repeat,
guint delay,
guint interval);
void (* set_tablet_mapping) (MetaInputSettings *settings,
ClutterInputDevice *device,
GDesktopTabletMapping mapping);
void (* set_tablet_keep_aspect) (MetaInputSettings *settings,
ClutterInputDevice *device,
MetaOutput *output,
gboolean keep_aspect);
void (* set_tablet_area) (MetaInputSettings *settings,
ClutterInputDevice *device,
gdouble padding_left,
gdouble padding_right,
gdouble padding_top,
gdouble padding_bottom);
};
GType meta_input_settings_get_type (void) G_GNUC_CONST;
MetaInputSettings * meta_input_settings_create (void);
MetaInputSettings * meta_input_settings_get (void);
GSettings * meta_input_settings_get_tablet_settings (MetaInputSettings *settings,
ClutterInputDevice *device);
MetaOutput * meta_input_settings_get_tablet_output (MetaInputSettings *settings,
ClutterInputDevice *device);
GDesktopTabletMapping meta_input_settings_get_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device);
GDesktopStylusButtonAction meta_input_settings_get_stylus_button_action (MetaInputSettings *settings,
ClutterInputDeviceTool *tool,
ClutterInputDevice *current_device,
guint button);
gdouble meta_input_settings_translate_tablet_tool_pressure (MetaInputSettings *input_settings,
ClutterInputDeviceTool *tool,
ClutterInputDevice *current_tablet,
gdouble pressure);
gboolean meta_input_settings_is_pad_button_grabbed (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
guint button);
gboolean meta_input_settings_handle_pad_button (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
gboolean is_press,
guint button);
gchar * meta_input_settings_get_pad_button_action_label (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
guint button);
#ifdef HAVE_LIBWACOM
WacomDevice * meta_input_settings_get_tablet_wacom_device (MetaInputSettings *settings,
ClutterInputDevice *device);
#endif
#endif /* META_INPUT_SETTINGS_PRIVATE_H */

View File

@ -38,8 +38,11 @@
#include "native/meta-input-settings-native.h"
#endif
#include <glib/gi18n-lib.h>
#include <meta/util.h>
static GQuark quark_tool_settings = 0;
typedef struct _MetaInputSettingsPrivate MetaInputSettingsPrivate;
typedef struct _DeviceMappingInfo DeviceMappingInfo;
@ -48,6 +51,9 @@ struct _DeviceMappingInfo
MetaInputSettings *input_settings;
ClutterInputDevice *device;
GSettings *settings;
#ifdef HAVE_LIBWACOM
WacomDevice *wacom_device;
#endif
};
struct _MetaInputSettingsPrivate
@ -62,6 +68,10 @@ struct _MetaInputSettingsPrivate
GSettings *keyboard_settings;
GHashTable *mappable_devices;
#ifdef HAVE_LIBWACOM
WacomDeviceDatabase *wacom_db;
#endif
};
typedef void (*ConfigBoolFunc) (MetaInputSettings *input_settings,
@ -122,6 +132,9 @@ meta_input_settings_dispose (GObject *object)
g_clear_object (&priv->monitor_manager);
if (priv->wacom_db)
libwacom_database_destroy (priv->wacom_db);
G_OBJECT_CLASS (meta_input_settings_parent_class)->dispose (object);
}
@ -595,6 +608,48 @@ meta_input_settings_find_output (MetaInputSettings *input_settings,
return NULL;
}
static void
update_tablet_keep_aspect (MetaInputSettings *input_settings,
GSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsClass *input_settings_class;
MetaOutput *output = NULL;
gboolean keep_aspect;
if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE)
return;
#ifdef HAVE_LIBWACOM
{
WacomDevice *wacom_device;
wacom_device = meta_input_settings_get_tablet_wacom_device (input_settings,
device);
/* Keep aspect only makes sense in external tablets */
if (wacom_device &&
libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE)
return;
}
#endif
input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
if (clutter_input_device_get_mapping_mode (device) ==
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE)
{
keep_aspect = g_settings_get_boolean (settings, "keep-aspect");
output = meta_input_settings_find_output (input_settings, settings, device);
}
else
{
keep_aspect = FALSE;
}
input_settings_class->set_tablet_keep_aspect (input_settings, device,
output, keep_aspect);
}
static void
update_device_display (MetaInputSettings *input_settings,
GSettings *settings,
@ -605,15 +660,138 @@ update_device_display (MetaInputSettings *input_settings,
gfloat matrix[6] = { 1, 0, 0, 0, 1, 0 };
MetaOutput *output;
if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE &&
clutter_input_device_get_device_type (device) != CLUTTER_TOUCHSCREEN_DEVICE)
return;
priv = meta_input_settings_get_instance_private (input_settings);
input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
output = meta_input_settings_find_output (input_settings, settings, device);
/* If mapping is relative, the device can move on all displays */
if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE ||
clutter_input_device_get_mapping_mode (device) ==
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE)
output = meta_input_settings_find_output (input_settings, settings, device);
else
output = NULL;
if (output)
meta_monitor_manager_get_monitor_matrix (priv->monitor_manager,
output, matrix);
input_settings_class->set_matrix (input_settings, device, matrix);
/* Ensure the keep-aspect mapping is updated */
update_tablet_keep_aspect (input_settings, settings, device);
}
static void
update_tablet_mapping (MetaInputSettings *input_settings,
GSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsClass *input_settings_class;
GDesktopTabletMapping mapping;
if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE)
return;
#ifdef HAVE_LIBWACOM
{
WacomDevice *wacom_device;
wacom_device = meta_input_settings_get_tablet_wacom_device (input_settings,
device);
/* Tablet mapping only makes sense on external tablets */
if (wacom_device &&
(libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE))
return;
}
#endif
input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
mapping = g_settings_get_enum (settings, "mapping");
settings_device_set_uint_setting (input_settings, device,
input_settings_class->set_tablet_mapping,
mapping);
/* Relative mapping disables keep-aspect/display */
update_tablet_keep_aspect (input_settings, settings, device);
update_device_display (input_settings, settings, device);
}
static void
update_tablet_area (MetaInputSettings *input_settings,
GSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsClass *input_settings_class;
GVariant *variant;
const gdouble *area;
gsize n_elems;
if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE)
return;
#ifdef HAVE_LIBWACOM
{
WacomDevice *wacom_device;
wacom_device = meta_input_settings_get_tablet_wacom_device (input_settings,
device);
/* Tablet area only makes sense on system/display integrated tablets */
if (wacom_device &&
(libwacom_get_integration_flags (wacom_device) &
(WACOM_DEVICE_INTEGRATED_SYSTEM | WACOM_DEVICE_INTEGRATED_DISPLAY)) == 0)
return;
}
#endif
input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
variant = g_settings_get_value (settings, "area");
area = g_variant_get_fixed_array (variant, &n_elems, sizeof (gdouble));
if (n_elems == 4)
{
input_settings_class->set_tablet_area (input_settings, device,
area[0], area[1],
area[2], area[3]);
}
g_variant_unref (variant);
}
static void
update_tablet_left_handed (MetaInputSettings *input_settings,
GSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsClass *input_settings_class;
gboolean enabled;
if (clutter_input_device_get_device_type (device) != CLUTTER_TABLET_DEVICE)
return;
#ifdef HAVE_LIBWACOM
{
WacomDevice *wacom_device;
wacom_device = meta_input_settings_get_tablet_wacom_device (input_settings,
device);
/* Left handed mode only makes sense on external tablets */
if (wacom_device &&
(libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE))
return;
}
#endif
input_settings_class = META_INPUT_SETTINGS_GET_CLASS (input_settings);
enabled = g_settings_get_boolean (settings, "left-handed");
settings_device_set_bool_setting (input_settings, device,
input_settings_class->set_left_handed,
enabled);
}
static void
@ -671,6 +849,30 @@ mapped_device_changed_cb (GSettings *settings,
{
if (strcmp (key, "display") == 0)
update_device_display (info->input_settings, settings, info->device);
else if (strcmp (key, "mapping") == 0)
update_tablet_mapping (info->input_settings, settings, info->device);
else if (strcmp (key, "area") == 0)
update_tablet_area (info->input_settings, settings, info->device);
else if (strcmp (key, "keep-aspect") == 0)
update_tablet_keep_aspect (info->input_settings, settings, info->device);
else if (strcmp (key, "left-handed") == 0)
update_tablet_left_handed (info->input_settings, settings, info->device);
}
static void
apply_mappable_device_settings (MetaInputSettings *input_settings,
DeviceMappingInfo *info)
{
update_device_display (input_settings, info->settings, info->device);
if (clutter_input_device_get_device_type (info->device) == CLUTTER_TABLET_DEVICE ||
clutter_input_device_get_device_type (info->device) == CLUTTER_PAD_DEVICE)
{
update_tablet_mapping (input_settings, info->settings, info->device);
update_tablet_area (input_settings, info->settings, info->device);
update_tablet_keep_aspect (input_settings, info->settings, info->device);
update_tablet_left_handed (input_settings, info->settings, info->device);
}
}
static GSettings *
@ -691,7 +893,8 @@ lookup_device_settings (ClutterInputDevice *device)
else if (type == CLUTTER_TABLET_DEVICE ||
type == CLUTTER_PEN_DEVICE ||
type == CLUTTER_ERASER_DEVICE ||
type == CLUTTER_CURSOR_DEVICE)
type == CLUTTER_CURSOR_DEVICE ||
type == CLUTTER_PAD_DEVICE)
{
group = "tablets";
schema = "org.gnome.desktop.peripherals.tablet";
@ -710,21 +913,86 @@ lookup_device_settings (ClutterInputDevice *device)
return settings;
}
static GSettings *
lookup_tool_settings (ClutterInputDeviceTool *tool,
ClutterInputDevice *device)
{
GSettings *settings;
guint64 serial;
gchar *path;
settings = g_object_get_qdata (G_OBJECT (tool), quark_tool_settings);
if (!settings)
{
serial = clutter_input_device_tool_get_serial (tool);
if (serial == 0)
{
path = g_strdup_printf ("/org/gnome/desktop/peripherals/stylus/default-%s:%s/",
clutter_input_device_get_vendor_id (device),
clutter_input_device_get_product_id (device));
}
else
{
path = g_strdup_printf ("/org/gnome/desktop/peripherals/stylus/%lx/", serial);
}
settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.stylus",
path);
g_object_set_qdata_full (G_OBJECT (tool), quark_tool_settings, settings,
(GDestroyNotify) g_object_unref);
g_free (path);
}
return settings;
}
static GSettings *
lookup_pad_button_settings (ClutterInputDevice *device,
guint button)
{
const gchar *vendor, *product;
GSettings *settings;
gchar *path;
vendor = clutter_input_device_get_vendor_id (device);
product = clutter_input_device_get_product_id (device);
path = g_strdup_printf ("/org/gnome/desktop/peripherals/tablets/%s:%s/button%c/",
vendor, product, 'A' + button);
settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.pad-button",
path);
g_free (path);
return settings;
}
static void
monitors_changed_cb (MetaMonitorManager *monitor_manager,
MetaInputSettings *input_settings)
{
MetaInputSettingsPrivate *priv;
ClutterInputDevice *device;
GSettings *settings;
DeviceMappingInfo *info;
GHashTableIter iter;
priv = meta_input_settings_get_instance_private (input_settings);
g_hash_table_iter_init (&iter, priv->mappable_devices);
while (g_hash_table_iter_next (&iter, (gpointer *) &device,
(gpointer *) &settings))
update_device_display (input_settings, settings, device);
(gpointer *) &info))
update_device_display (input_settings, info->settings, device);
}
static void
device_mapping_info_free (DeviceMappingInfo *info)
{
#ifdef HAVE_LIBWACOM
if (info->wacom_device)
libwacom_destroy (info->wacom_device);
#endif
g_object_unref (info->settings);
g_slice_free (DeviceMappingInfo, info);
}
static gboolean
@ -742,18 +1010,37 @@ check_add_mappable_device (MetaInputSettings *input_settings,
priv = meta_input_settings_get_instance_private (input_settings);
info = g_new0 (DeviceMappingInfo, 1);
info = g_slice_new0 (DeviceMappingInfo);
info->input_settings = input_settings;
info->device = device;
info->settings = settings;
g_signal_connect_data (settings, "changed",
G_CALLBACK (mapped_device_changed_cb),
info, (GClosureNotify) g_free, 0);
#ifdef HAVE_LIBWACOM
if (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE ||
clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE)
{
WacomError *error = libwacom_error_new ();
g_hash_table_insert (priv->mappable_devices, device, settings);
info->wacom_device = libwacom_new_from_path (priv->wacom_db,
clutter_input_device_get_device_node (device),
WFALLBACK_NONE, error);
if (!info->wacom_device)
{
g_warning ("Could not get tablet information for '%s': %s",
clutter_input_device_get_device_name (device),
libwacom_error_get_message (error));
}
update_device_display (input_settings, settings, device);
libwacom_error_free (&error);
}
#endif
g_signal_connect (settings, "changed",
G_CALLBACK (mapped_device_changed_cb), info);
g_hash_table_insert (priv->mappable_devices, device, info);
apply_mappable_device_settings (input_settings, info);
return TRUE;
}
@ -837,6 +1124,9 @@ meta_input_settings_class_init (MetaInputSettingsClass *klass)
object_class->dispose = meta_input_settings_dispose;
object_class->constructed = meta_input_settings_constructed;
quark_tool_settings =
g_quark_from_static_string ("meta-input-settings-tool-settings");
}
static void
@ -868,14 +1158,21 @@ meta_input_settings_init (MetaInputSettings *settings)
G_CALLBACK (meta_input_settings_changed_cb), settings);
priv->mappable_devices =
g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref);
g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) device_mapping_info_free);
priv->monitor_manager = g_object_ref (meta_monitor_manager_get ());
g_signal_connect (priv->monitor_manager, "monitors-changed",
G_CALLBACK (monitors_changed_cb), settings);
priv->wacom_db = libwacom_database_new ();
if (!priv->wacom_db)
{
g_warning ("Could not create database of Wacom devices, "
"expect tablets to misbehave");
}
}
MetaInputSettings *
static MetaInputSettings *
meta_input_settings_create (void)
{
#ifdef HAVE_NATIVE_BACKEND
@ -891,3 +1188,355 @@ meta_input_settings_create (void)
return NULL;
}
MetaInputSettings *
meta_input_settings_get (void)
{
static MetaInputSettings *input_settings = NULL;
if (g_once_init_enter (&input_settings))
{
MetaInputSettings *settings = meta_input_settings_create ();
g_once_init_leave (&input_settings, settings);
}
return input_settings;
}
GSettings *
meta_input_settings_get_tablet_settings (MetaInputSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsPrivate *priv;
DeviceMappingInfo *info;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (settings), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
priv = meta_input_settings_get_instance_private (settings);
info = g_hash_table_lookup (priv->mappable_devices, device);
return info ? g_object_ref (info->settings) : NULL;
}
MetaOutput *
meta_input_settings_get_tablet_output (MetaInputSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsPrivate *priv;
DeviceMappingInfo *info;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (settings), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
priv = meta_input_settings_get_instance_private (settings);
info = g_hash_table_lookup (priv->mappable_devices, device);
if (!info)
return NULL;
return meta_input_settings_find_output (settings, info->settings, device);
}
GDesktopTabletMapping
meta_input_settings_get_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsPrivate *priv;
DeviceMappingInfo *info;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (settings),
G_DESKTOP_TABLET_MAPPING_ABSOLUTE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
G_DESKTOP_TABLET_MAPPING_ABSOLUTE);
priv = meta_input_settings_get_instance_private (settings);
info = g_hash_table_lookup (priv->mappable_devices, device);
g_return_val_if_fail (info != NULL, G_DESKTOP_TABLET_MAPPING_ABSOLUTE);
return g_settings_get_enum (info->settings, "mapping");
}
GDesktopStylusButtonAction
meta_input_settings_get_stylus_button_action (MetaInputSettings *input_settings,
ClutterInputDeviceTool *tool,
ClutterInputDevice *current_tablet,
guint button)
{
GSettings *settings;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings),
G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool),
G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT);
settings = lookup_tool_settings (tool, current_tablet);
if (button == 2)
return g_settings_get_enum (settings, "button-action");
else if (button == 3)
return g_settings_get_enum (settings, "secondary-button-action");
else
return G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT;
}
static GDesktopPadButtonAction
meta_input_settings_get_pad_button_action (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
guint button)
{
GDesktopPadButtonAction action;
GSettings *settings;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings),
G_DESKTOP_PAD_BUTTON_ACTION_NONE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad),
G_DESKTOP_PAD_BUTTON_ACTION_NONE);
settings = lookup_pad_button_settings (pad, button);
action = g_settings_get_enum (settings, "action");
g_object_unref (settings);
return action;
}
#ifdef HAVE_LIBWACOM
WacomDevice *
meta_input_settings_get_tablet_wacom_device (MetaInputSettings *settings,
ClutterInputDevice *device)
{
MetaInputSettingsPrivate *priv;
DeviceMappingInfo *info;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (settings), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
priv = meta_input_settings_get_instance_private (settings);
info = g_hash_table_lookup (priv->mappable_devices, device);
g_return_val_if_fail (info != NULL, NULL);
return info->wacom_device;
}
#endif /* HAVE_LIBWACOM */
static gboolean
cycle_outputs (MetaInputSettings *settings,
MetaOutput *current_output,
MetaOutput **next_output)
{
MetaInputSettingsPrivate *priv;
MetaOutput *next, *outputs;
guint n_outputs, current, i;
priv = meta_input_settings_get_instance_private (settings);
outputs = meta_monitor_manager_get_outputs (priv->monitor_manager,
&n_outputs);
if (n_outputs <= 1)
return FALSE;
/* We cycle between:
* - the span of all monitors (current_output = NULL)
* - each monitor individually.
*/
if (!current_output)
{
next = &outputs[0];
}
else
{
for (i = 0; i < n_outputs; i++)
{
if (current_output != &outputs[i])
continue;
current = i;
break;
}
g_assert (i < n_outputs);
if (current == n_outputs - 1)
next = NULL;
else
next = &outputs[current + 1];
}
*next_output = next;
return TRUE;
}
static void
meta_input_settings_cycle_tablet_output (MetaInputSettings *input_settings,
ClutterInputDevice *device)
{
MetaInputSettingsPrivate *priv;
DeviceMappingInfo *info;
MetaOutput *output;
const gchar *edid[4] = { 0 };
g_return_if_fail (META_IS_INPUT_SETTINGS (input_settings));
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
g_return_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE ||
clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE);
priv = meta_input_settings_get_instance_private (input_settings);
info = g_hash_table_lookup (priv->mappable_devices, device);
g_return_if_fail (info != NULL);
#ifdef HAVE_LIBWACOM
/* Output rotation only makes sense on external tablets */
if (info->wacom_device &&
(libwacom_get_integration_flags (info->wacom_device) != WACOM_DEVICE_INTEGRATED_NONE))
return;
#endif
output = meta_input_settings_find_output (input_settings,
info->settings, device);
if (!cycle_outputs (input_settings, output, &output))
return;
edid[0] = output ? output->vendor : "";
edid[1] = output ? output->product : "";
edid[2] = output ? output->serial : "";
g_settings_set_strv (info->settings, "display", edid);
}
static gdouble
calculate_bezier_position (gdouble pos,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2)
{
gdouble int1_y, int2_y;
pos = CLAMP (pos, 0, 1);
/* Intersection between 0,0 and x1,y1 */
int1_y = pos * y1;
/* Intersection between x2,y2 and 1,1 */
int2_y = (pos * (1 - y2)) + y2;
/* Find the new position in the line traced by the previous points */
return (pos * (int2_y - int1_y)) + int1_y;
}
gdouble
meta_input_settings_translate_tablet_tool_pressure (MetaInputSettings *input_settings,
ClutterInputDeviceTool *tool,
ClutterInputDevice *current_tablet,
gdouble pressure)
{
GSettings *settings;
GVariant *variant;
const gint32 *curve;
gsize n_elems;
pressure = CLAMP (pressure, 0, 1);
g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), pressure);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), pressure);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (current_tablet), pressure);
settings = lookup_tool_settings (tool, current_tablet);
if (clutter_input_device_tool_get_tool_type (tool) == CLUTTER_INPUT_DEVICE_TOOL_ERASER)
variant = g_settings_get_value (settings, "eraser-pressure-curve");
else
variant = g_settings_get_value (settings, "pressure-curve");
curve = g_variant_get_fixed_array (variant, &n_elems, sizeof (gint32));
if (n_elems != 4)
return pressure;
pressure = calculate_bezier_position (pressure,
(gdouble) curve[0] / 100,
(gdouble) curve[1] / 100,
(gdouble) curve[2] / 100,
(gdouble) curve[3] / 100);
g_variant_unref (variant);
return pressure;
}
gboolean
meta_input_settings_is_pad_button_grabbed (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
guint button)
{
g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), FALSE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), FALSE);
g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
CLUTTER_PAD_DEVICE, FALSE);
return (meta_input_settings_get_pad_button_action (input_settings, pad, button) !=
G_DESKTOP_PAD_BUTTON_ACTION_NONE);
}
gboolean
meta_input_settings_handle_pad_button (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
gboolean is_press,
guint button)
{
GDesktopPadButtonAction action;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), FALSE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), FALSE);
g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
CLUTTER_PAD_DEVICE, FALSE);
action = meta_input_settings_get_pad_button_action (input_settings, pad, button);
switch (action)
{
case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
if (is_press)
meta_input_settings_cycle_tablet_output (input_settings, pad);
return TRUE;
case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
if (is_press)
meta_display_request_pad_osd (meta_get_display (), pad, FALSE);
return TRUE;
case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
default:
return FALSE;
}
}
gchar *
meta_input_settings_get_pad_button_action_label (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
guint button)
{
GDesktopPadButtonAction action;
g_return_val_if_fail (META_IS_INPUT_SETTINGS (input_settings), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), NULL);
g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
CLUTTER_PAD_DEVICE, NULL);
action = meta_input_settings_get_pad_button_action (input_settings, pad, button);
switch (action)
{
case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
{
GSettings *settings;
gchar *accel;
settings = lookup_pad_button_settings (pad, button);
accel = g_settings_get_string (settings, "keybinding");
g_object_unref (settings);
return accel;
}
case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
return g_strdup (_("Switch monitor"));
case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
return g_strdup (_("Show on-screen help"));
case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
default:
return NULL;
}
}

View File

@ -241,6 +241,43 @@ meta_input_settings_native_set_keyboard_repeat (MetaInputSettings *settings,
clutter_evdev_set_keyboard_repeat (manager, enabled, delay, interval);
}
static void
meta_input_settings_native_set_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device,
GDesktopTabletMapping mapping)
{
ClutterInputDeviceMapping dev_mapping;
if (mapping == G_DESKTOP_TABLET_MAPPING_ABSOLUTE)
dev_mapping = CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE;
else if (mapping == G_DESKTOP_TABLET_MAPPING_RELATIVE)
dev_mapping = CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE;
else
return;
clutter_input_device_set_mapping_mode (device, dev_mapping);
}
static void
meta_input_settings_native_set_tablet_keep_aspect (MetaInputSettings *settings,
ClutterInputDevice *device,
MetaOutput *output,
gboolean keep_aspect)
{
/* FIXME: Implement */
}
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)
{
/* FIXME: Implement */
}
static void
meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass)
{
@ -256,6 +293,10 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass)
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_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;
}
static void

View File

@ -305,6 +305,31 @@ meta_input_settings_x11_set_keyboard_repeat (MetaInputSettings *settings,
}
}
static void
meta_input_settings_x11_set_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device,
GDesktopTabletMapping mapping)
{
}
static void
meta_input_settings_x11_set_tablet_keep_aspect (MetaInputSettings *settings,
ClutterInputDevice *device,
MetaOutput *output,
gboolean keep_aspect)
{
}
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)
{
}
static void
meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass)
{
@ -320,6 +345,10 @@ meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass)
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;
}
static void

View File

@ -277,6 +277,8 @@ struct _MetaDisplay
int xinput_event_base;
int xinput_opcode;
ClutterActor *current_pad_osd;
MetaStartupNotification *startup_notification;
int xsync_event_base;

View File

@ -53,6 +53,7 @@
#include "backends/native/meta-backend-native.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/meta-stage.h"
#include "backends/meta-input-settings-private.h"
#include <clutter/x11/clutter-x11.h>
#ifdef HAVE_RANDR
@ -75,6 +76,8 @@
#ifdef HAVE_WAYLAND
#include "wayland/meta-xwayland-private.h"
#include "wayland/meta-wayland-tablet-seat.h"
#include "wayland/meta-wayland-tablet-pad.h"
#endif
/*
@ -126,6 +129,7 @@ enum
RESTART,
SHOW_RESIZE_POPUP,
GL_VIDEO_MEMORY_PURGED,
SHOW_PAD_OSD,
LAST_SIGNAL
};
@ -351,6 +355,27 @@ meta_display_class_init (MetaDisplayClass *klass)
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* MetaDisplay::show-pad-osd:
* @display: the #MetaDisplay instance
* @pad: the pad device
* @settings: the pad device settings
* @layout_path: path to the layout image
* @edition_mode: Whether the OSD should be shown in edition mode
* @monitor_idx: Monitor to show the OSD on
*
* Requests the pad button mapping OSD to be shown.
*
* Returns: (transfer none) (nullable): The OSD actor
*/
display_signals[SHOW_PAD_OSD] =
g_signal_new ("show-pad-osd",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
CLUTTER_TYPE_ACTOR, 5, CLUTTER_TYPE_INPUT_DEVICE,
G_TYPE_SETTINGS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INT);
g_object_class_install_property (object_class,
PROP_FOCUS_WINDOW,
g_param_spec_object ("focus-window",
@ -528,6 +553,27 @@ on_startup_notification_changed (MetaStartupNotification *sn,
g_signal_emit_by_name (display->screen, "startup-sequence-changed", sequence);
}
static void
check_pad_removed (MetaDisplay *display,
ClutterInputDevice *device,
ClutterDeviceManager *device_manager)
{
ClutterInputDevice *pad;
if (!display->current_pad_osd)
return;
pad = g_object_get_data (G_OBJECT (display->current_pad_osd),
"meta-pad-osd-device");
if (pad == device)
{
/* Close pad OSD */
clutter_actor_destroy (display->current_pad_osd);
display->current_pad_osd = NULL;
}
}
/**
* meta_display_open:
*
@ -951,6 +997,10 @@ meta_display_open (void)
meta_idle_monitor_init_dbus ();
g_signal_connect_swapped (clutter_device_manager_get_default (),
"device-removed", G_CALLBACK (check_pad_removed),
display);
/* Done opening new display */
display->display_opening = FALSE;
@ -3070,3 +3120,114 @@ meta_display_set_alarm_filter (MetaDisplay *display,
display->alarm_filter = filter;
display->alarm_filter_data = data;
}
void
meta_display_request_pad_osd (MetaDisplay *display,
ClutterInputDevice *pad,
gboolean edition_mode)
{
MetaInputSettings *input_settings;
const gchar *layout_path = NULL;
ClutterActor *osd;
MetaOutput *output;
gint monitor_idx;
GSettings *settings;
#ifdef HAVE_LIBWACOM
WacomDevice *wacom_device;
#endif
input_settings = meta_input_settings_get ();
if (display->current_pad_osd)
{
clutter_actor_destroy (display->current_pad_osd);
display->current_pad_osd = NULL;
}
if (input_settings)
{
settings = meta_input_settings_get_tablet_settings (input_settings, pad);
output = meta_input_settings_get_tablet_output (input_settings, pad);
#ifdef HAVE_LIBWACOM
wacom_device = meta_input_settings_get_tablet_wacom_device (input_settings,
pad);
layout_path = libwacom_get_layout_filename (wacom_device);
#endif
}
if (!layout_path || !settings)
return;
if (output && output->crtc)
{
monitor_idx = meta_screen_get_monitor_index_for_rect (display->screen,
&output->crtc->rect);
}
else
{
monitor_idx = meta_screen_get_current_monitor (display->screen);
}
g_signal_emit (display, display_signals[SHOW_PAD_OSD], 0,
pad, settings, layout_path,
edition_mode, monitor_idx, &osd);
if (osd)
{
display->current_pad_osd = osd;
g_object_set_data (G_OBJECT (display->current_pad_osd),
"meta-pad-osd-device", pad);
g_object_add_weak_pointer (G_OBJECT (display->current_pad_osd),
(gpointer *) &display->current_pad_osd);
clutter_actor_grab_key_focus (osd);
}
g_object_unref (settings);
}
gchar *
meta_display_get_pad_action_label (MetaDisplay *display,
ClutterInputDevice *pad,
MetaPadActionType action_type,
guint action_number)
{
gchar *label;
/* First, lookup the action, as imposed by settings */
if (action_type == META_PAD_ACTION_BUTTON)
{
MetaInputSettings *settings;
settings = meta_input_settings_get ();
label = meta_input_settings_get_pad_button_action_label (settings, pad, action_number);
if (label)
return label;
}
#ifdef HAVE_WAYLAND
/* Second, if this wayland, lookup the actions set by the clients */
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor;
MetaWaylandTabletSeat *tablet_seat;
MetaWaylandTabletPad *tablet_pad = NULL;
compositor = meta_wayland_compositor_get_default ();
tablet_seat = meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager,
compositor->seat);
if (tablet_seat)
tablet_pad = meta_wayland_tablet_seat_lookup_pad (tablet_seat, pad);
if (tablet_pad)
{
label = meta_wayland_tablet_pad_get_label (tablet_pad, action_type,
action_number);
}
if (label)
return label;
}
#endif
return NULL;
}

View File

@ -299,6 +299,12 @@ meta_display_handle_event (MetaDisplay *display,
goto out;
}
if (display->current_pad_osd)
{
bypass_wayland = TRUE;
goto out;
}
if (window)
{
/* Events that are likely to trigger compositor gestures should

View File

@ -53,6 +53,13 @@ typedef enum
META_TAB_SHOW_INSTANTLY /* Alt-Esc mode */
} MetaTabShowType;
typedef enum
{
META_PAD_ACTION_BUTTON, /* Action is a button */
META_PAD_ACTION_RING, /* Action is a ring */
META_PAD_ACTION_STRIP, /* Action is a strip */
} MetaPadActionType;
typedef struct _MetaDisplayClass MetaDisplayClass;
#define META_TYPE_DISPLAY (meta_display_get_type ())
@ -181,4 +188,12 @@ void meta_display_unfreeze_keyboard (MetaDisplay *display,
gboolean meta_display_is_pointer_emulating_sequence (MetaDisplay *display,
ClutterEventSequence *sequence);
void meta_display_request_pad_osd (MetaDisplay *display,
ClutterInputDevice *pad,
gboolean edition_mode);
gchar * meta_display_get_pad_action_label (MetaDisplay *display,
ClutterInputDevice *pad,
MetaPadActionType action_type,
guint action_number);
#endif

View File

@ -26,6 +26,7 @@
#include "meta-wayland-private.h"
#include "meta-wayland-versions.h"
#include "meta-wayland-data-device.h"
#include "meta-wayland-tablet-seat.h"
#define CAPABILITY_ENABLED(prev, cur, capability) ((cur & (capability)) && !(prev & (capability)))
#define CAPABILITY_DISABLED(prev, cur, capability) ((prev & (capability)) && !(cur & (capability)))
@ -369,11 +370,17 @@ void
meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat,
MetaWaylandSurface *surface)
{
if ((seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0)
return;
MetaWaylandTabletSeat *tablet_seat;
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
meta_wayland_keyboard_set_focus (&seat->keyboard, surface);
meta_wayland_data_device_set_keyboard_focus (&seat->data_device);
if ((seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0)
{
meta_wayland_keyboard_set_focus (&seat->keyboard, surface);
meta_wayland_data_device_set_keyboard_focus (&seat->data_device);
}
tablet_seat = meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat);
meta_wayland_tablet_seat_set_pad_focus (tablet_seat, surface);
}
gboolean

View File

@ -28,10 +28,10 @@
#include "meta-xwayland.h"
#include "screen-private.h"
struct _MetaWaylandSurfaceRoleCursor
{
MetaWaylandSurfaceRole parent;
typedef struct _MetaWaylandSurfaceRoleCursorPrivate MetaWaylandSurfaceRoleCursorPrivate;
struct _MetaWaylandSurfaceRoleCursorPrivate
{
int hot_x;
int hot_y;
MetaCursorSprite *cursor_sprite;
@ -39,41 +39,42 @@ struct _MetaWaylandSurfaceRoleCursor
MetaWaylandBuffer *buffer;
};
G_DEFINE_TYPE (MetaWaylandSurfaceRoleCursor,
meta_wayland_surface_role_cursor,
META_TYPE_WAYLAND_SURFACE_ROLE)
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandSurfaceRoleCursor,
meta_wayland_surface_role_cursor,
META_TYPE_WAYLAND_SURFACE_ROLE)
static void
update_cursor_sprite_texture (MetaWaylandSurfaceRoleCursor *cursor_role)
{
MetaWaylandSurfaceRoleCursorPrivate *priv = meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (cursor_role));
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
MetaCursorSprite *cursor_sprite = cursor_role->cursor_sprite;
MetaCursorSprite *cursor_sprite = priv->cursor_sprite;
g_return_if_fail (!buffer || buffer->texture);
if (!cursor_role->cursor_renderer || !cursor_sprite)
if (!priv->cursor_renderer || !cursor_sprite)
return;
if (buffer)
{
meta_cursor_sprite_set_texture (cursor_sprite,
buffer->texture,
cursor_role->hot_x * surface->scale,
cursor_role->hot_y * surface->scale);
priv->hot_x * surface->scale,
priv->hot_y * surface->scale);
if (cursor_role->buffer)
if (priv->buffer)
{
struct wl_resource *buffer_resource;
g_assert (cursor_role->buffer == buffer);
g_assert (priv->buffer == buffer);
buffer_resource = buffer->resource;
meta_cursor_renderer_realize_cursor_from_wl_buffer (cursor_role->cursor_renderer,
meta_cursor_renderer_realize_cursor_from_wl_buffer (priv->cursor_renderer,
cursor_sprite,
buffer_resource);
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
g_clear_object (&priv->buffer);
}
}
else
@ -81,7 +82,7 @@ update_cursor_sprite_texture (MetaWaylandSurfaceRoleCursor *cursor_role)
meta_cursor_sprite_set_texture (cursor_sprite, NULL, 0, 0);
}
meta_cursor_renderer_force_update (cursor_role->cursor_renderer);
meta_cursor_renderer_force_update (priv->cursor_renderer);
}
static void
@ -111,13 +112,15 @@ cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (buffer)
{
g_set_object (&cursor_role->buffer, buffer);
g_set_object (&priv->buffer, buffer);
meta_wayland_surface_ref_buffer_use_count (surface);
}
@ -130,13 +133,15 @@ cursor_surface_role_pre_commit (MetaWaylandSurfaceRole *surface_role,
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
if (pending->newly_attached && cursor_role->buffer)
if (pending->newly_attached && priv->buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
g_clear_object (&priv->buffer);
}
}
@ -146,14 +151,16 @@ cursor_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (pending->newly_attached)
{
g_set_object (&cursor_role->buffer, buffer);
if (cursor_role->buffer)
g_set_object (&priv->buffer, buffer);
if (priv->buffer)
meta_wayland_surface_ref_buffer_use_count (surface);
}
@ -171,10 +178,12 @@ cursor_surface_role_is_on_output (MetaWaylandSurfaceRole *role,
meta_wayland_surface_role_get_surface (role);
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
MetaRectangle rect;
rect = meta_cursor_renderer_calculate_rect (cursor_role->cursor_renderer,
cursor_role->cursor_sprite);
rect = meta_cursor_renderer_calculate_rect (priv->cursor_renderer,
priv->cursor_sprite);
return meta_rectangle_overlap (&rect, &monitor->rect);
}
@ -183,19 +192,21 @@ cursor_surface_role_dispose (GObject *object)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (object);
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
g_signal_handlers_disconnect_by_func (cursor_role->cursor_sprite,
g_signal_handlers_disconnect_by_func (priv->cursor_sprite,
cursor_sprite_prepare_at, cursor_role);
g_clear_object (&cursor_role->cursor_renderer);
g_clear_object (&cursor_role->cursor_sprite);
g_clear_object (&priv->cursor_renderer);
g_clear_object (&priv->cursor_sprite);
if (cursor_role->buffer)
if (priv->buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
g_clear_object (&priv->buffer);
}
G_OBJECT_CLASS (meta_wayland_surface_role_cursor_parent_class)->dispose (object);
@ -204,8 +215,11 @@ cursor_surface_role_dispose (GObject *object)
static void
meta_wayland_surface_role_cursor_init (MetaWaylandSurfaceRoleCursor *role)
{
role->cursor_sprite = meta_cursor_sprite_new ();
g_signal_connect_object (role->cursor_sprite,
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (role);
priv->cursor_sprite = meta_cursor_sprite_new ();
g_signal_connect_object (priv->cursor_sprite,
"prepare-at",
G_CALLBACK (cursor_sprite_prepare_at),
role,
@ -230,7 +244,10 @@ meta_wayland_surface_role_cursor_class_init (MetaWaylandSurfaceRoleCursorClass *
MetaCursorSprite *
meta_wayland_surface_role_cursor_get_sprite (MetaWaylandSurfaceRoleCursor *cursor_role)
{
return cursor_role->cursor_sprite;
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
return priv->cursor_sprite;
}
void
@ -238,12 +255,15 @@ meta_wayland_surface_role_cursor_set_hotspot (MetaWaylandSurfaceRoleCursor *curs
gint hotspot_x,
gint hotspot_y)
{
if (cursor_role->hot_x == hotspot_x &&
cursor_role->hot_y == hotspot_y)
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
if (priv->hot_x == hotspot_x &&
priv->hot_y == hotspot_y)
return;
cursor_role->hot_x = hotspot_x;
cursor_role->hot_y = hotspot_y;
priv->hot_x = hotspot_x;
priv->hot_y = hotspot_y;
update_cursor_sprite_texture (cursor_role);
}
@ -252,30 +272,39 @@ meta_wayland_surface_role_cursor_get_hotspot (MetaWaylandSurfaceRoleCursor *curs
gint *hotspot_x,
gint *hotspot_y)
{
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
if (hotspot_x)
*hotspot_x = cursor_role->hot_x;
*hotspot_x = priv->hot_x;
if (hotspot_y)
*hotspot_y = cursor_role->hot_y;
*hotspot_y = priv->hot_y;
}
void
meta_wayland_surface_role_cursor_set_renderer (MetaWaylandSurfaceRoleCursor *cursor_role,
MetaCursorRenderer *renderer)
{
if (cursor_role->cursor_renderer == renderer)
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
if (priv->cursor_renderer == renderer)
return;
if (renderer)
g_object_ref (renderer);
if (cursor_role->cursor_renderer)
g_object_unref (cursor_role->cursor_renderer);
if (priv->cursor_renderer)
g_object_unref (priv->cursor_renderer);
cursor_role->cursor_renderer = renderer;
priv->cursor_renderer = renderer;
update_cursor_sprite_texture (cursor_role);
}
MetaCursorRenderer *
meta_wayland_surface_role_cursor_get_renderer (MetaWaylandSurfaceRoleCursor *cursor_role)
{
return cursor_role->cursor_renderer;
MetaWaylandSurfaceRoleCursorPrivate *priv =
meta_wayland_surface_role_cursor_get_instance_private (cursor_role);
return priv->cursor_renderer;
}

View File

@ -25,11 +25,16 @@
#include "meta-wayland-surface.h"
#include "backends/meta-cursor-renderer.h"
struct _MetaWaylandSurfaceRoleCursorClass
{
MetaWaylandSurfaceRoleClass parent_class;
};
#define META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR (meta_wayland_surface_role_cursor_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleCursor,
meta_wayland_surface_role_cursor,
META, WAYLAND_SURFACE_ROLE_CURSOR,
MetaWaylandSurfaceRole);
G_DECLARE_DERIVABLE_TYPE (MetaWaylandSurfaceRoleCursor,
meta_wayland_surface_role_cursor,
META, WAYLAND_SURFACE_ROLE_CURSOR,
MetaWaylandSurfaceRole);
MetaCursorSprite * meta_wayland_surface_role_cursor_get_sprite (MetaWaylandSurfaceRoleCursor *cursor_role);

View File

@ -0,0 +1,42 @@
/*
* Wayland Support
*
* Copyright (C) 2016 Red Hat, Inc.
*
* 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.
*/
#include "config.h"
#include "meta-wayland-surface-role-tablet-cursor.h"
struct _MetaWaylandSurfaceRoleTabletCursor
{
MetaWaylandSurfaceRoleCursor parent;
};
G_DEFINE_TYPE (MetaWaylandSurfaceRoleTabletCursor,
meta_wayland_surface_role_tablet_cursor,
META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR)
static void
meta_wayland_surface_role_tablet_cursor_init (MetaWaylandSurfaceRoleTabletCursor *role)
{
}
static void
meta_wayland_surface_role_tablet_cursor_class_init (MetaWaylandSurfaceRoleTabletCursorClass *klass)
{
}

View File

@ -0,0 +1,33 @@
/*
* Wayland Support
*
* Copyright (C) 2016 Red Hat, Inc.
*
* 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.
*/
#ifndef META_WAYLAND_SURFACE_ROLE_TABLET_CURSOR_H
#define META_WAYLAND_SURFACE_ROLE_TABLET_CURSOR_H
#include "meta-wayland-surface-role-cursor.h"
#define META_TYPE_WAYLAND_SURFACE_ROLE_TABLET_CURSOR (meta_wayland_surface_role_tablet_cursor_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleTabletCursor,
meta_wayland_surface_role_tablet_cursor,
META, WAYLAND_SURFACE_ROLE_TABLET_CURSOR,
MetaWaylandSurfaceRoleCursor);
#endif /* META_WAYLAND_SURFACE_ROLE_TABLET_CURSOR_H */

View File

@ -28,7 +28,7 @@
#include <glib.h>
#include <wayland-server.h>
#include "tablet-unstable-v1-server-protocol.h"
#include "tablet-unstable-v2-server-protocol.h"
#include "meta-wayland-private.h"
#include "meta-wayland-tablet-manager.h"
@ -54,7 +54,8 @@ is_tablet_device (ClutterInputDevice *device)
return (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE ||
device_type == CLUTTER_CURSOR_DEVICE);
device_type == CLUTTER_CURSOR_DEVICE ||
device_type == CLUTTER_PAD_DEVICE);
}
static void
@ -79,7 +80,7 @@ tablet_manager_destroy (struct wl_client *client,
wl_resource_destroy (resource);
}
static const struct zwp_tablet_manager_v1_interface tablet_manager_interface = {
static const struct zwp_tablet_manager_v2_interface tablet_manager_interface = {
tablet_manager_get_tablet_seat,
tablet_manager_destroy
};
@ -94,7 +95,7 @@ bind_tablet_manager (struct wl_client *client,
MetaWaylandTabletManager *tablet_manager = compositor->tablet_manager;
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_manager_v1_interface,
resource = wl_resource_create (client, &zwp_tablet_manager_v2_interface,
MIN (version, 1), id);
wl_resource_set_implementation (resource, &tablet_manager_interface,
tablet_manager, unbind_resource);
@ -116,7 +117,7 @@ meta_wayland_tablet_manager_new (MetaWaylandCompositor *compositor)
wl_list_init (&tablet_manager->resource_list);
wl_global_create (tablet_manager->wl_display,
&zwp_tablet_manager_v1_interface, 1,
&zwp_tablet_manager_v2_interface, 1,
compositor, bind_tablet_manager);
return tablet_manager;
@ -155,7 +156,8 @@ meta_wayland_tablet_manager_lookup_seat (MetaWaylandTabletManager *manager,
while (g_hash_table_iter_next (&iter, (gpointer*) &seat, (gpointer*) &tablet_seat))
{
if (meta_wayland_tablet_seat_lookup_tablet (tablet_seat, device))
if (meta_wayland_tablet_seat_lookup_tablet (tablet_seat, device) ||
meta_wayland_tablet_seat_lookup_pad (tablet_seat, device))
return tablet_seat;
}
@ -190,6 +192,10 @@ meta_wayland_tablet_manager_update (MetaWaylandTabletManager *manager,
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_RING:
case CLUTTER_PAD_STRIP:
meta_wayland_tablet_seat_update (tablet_seat, event);
break;
default:
@ -216,6 +222,10 @@ meta_wayland_tablet_manager_handle_event (MetaWaylandTabletManager *manager,
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_RING:
case CLUTTER_PAD_STRIP:
return meta_wayland_tablet_seat_handle_event (tablet_seat, event);
default:
return CLUTTER_EVENT_PROPAGATE;
@ -232,7 +242,7 @@ meta_wayland_tablet_manager_ensure_seat (MetaWaylandTabletManager *manager,
if (!tablet_seat)
{
tablet_seat = meta_wayland_tablet_seat_new (manager);
tablet_seat = meta_wayland_tablet_seat_new (manager, seat);
g_hash_table_insert (manager->seats, seat, tablet_seat);
}

View File

@ -0,0 +1,458 @@
/*
* Wayland Support
*
* Copyright (C) 2016 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>
*/
#define _GNU_SOURCE
#include "config.h"
#include <wayland-server.h>
#include "tablet-unstable-v2-server-protocol.h"
#include "meta-surface-actor-wayland.h"
#include "meta-wayland-tablet-seat.h"
#include "meta-wayland-tablet-pad.h"
#include "meta-wayland-tablet-pad-group.h"
#include "meta-wayland-tablet-pad-ring.h"
#include "meta-wayland-tablet-pad-strip.h"
#ifdef HAVE_NATIVE_BACKEND
#include <clutter/evdev/clutter-evdev.h>
#include "backends/native/meta-backend-native.h"
#endif
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
MetaWaylandTabletPadGroup *
meta_wayland_tablet_pad_group_new (MetaWaylandTabletPad *pad)
{
MetaWaylandTabletPadGroup *group;
group = g_slice_new0 (MetaWaylandTabletPadGroup);
wl_list_init (&group->resource_list);
wl_list_init (&group->focus_resource_list);
group->pad = pad;
return group;
}
void
meta_wayland_tablet_pad_group_free (MetaWaylandTabletPadGroup *group)
{
struct wl_resource *resource, *next;
wl_resource_for_each_safe (resource, next, &group->resource_list)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
g_list_free (group->rings);
g_list_free (group->strips);
g_slice_free (MetaWaylandTabletPadGroup, group);
}
static void
tablet_pad_group_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_pad_group_v2_interface group_interface = {
tablet_pad_group_destroy
};
struct wl_resource *
meta_wayland_tablet_pad_group_create_new_resource (MetaWaylandTabletPadGroup *group,
struct wl_client *client,
struct wl_resource *pad_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_pad_group_v2_interface,
wl_resource_get_version (pad_resource), id);
wl_resource_set_implementation (resource, &group_interface,
group, unbind_resource);
wl_resource_set_user_data (resource, group);
wl_list_insert (&group->resource_list, wl_resource_get_link (resource));
return resource;
}
struct wl_resource *
meta_wayland_tablet_pad_group_lookup_resource (MetaWaylandTabletPadGroup *group,
struct wl_client *client)
{
struct wl_resource *resource;
resource = wl_resource_find_for_client (&group->resource_list, client);
if (!resource)
resource = wl_resource_find_for_client (&group->focus_resource_list, client);
return resource;
}
static guint
tablet_pad_group_get_current_mode (MetaWaylandTabletPadGroup *group)
{
MetaBackend *backend = meta_get_backend ();
#ifdef HAVE_NATIVE_BACKEND
if (META_IS_BACKEND_NATIVE (backend))
{
struct libinput_device *libinput_device;
struct libinput_tablet_pad_mode_group *mode_group;
guint n_group;
libinput_device = clutter_evdev_input_device_get_libinput_device (group->pad->device);
n_group = g_list_index (group->pad->groups, group);
mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, n_group);
return libinput_tablet_pad_mode_group_get_mode (mode_group);
}
else
#endif
return 0;
}
static guint
tablet_pad_group_get_n_modes (MetaWaylandTabletPadGroup *group)
{
MetaBackend *backend = meta_get_backend ();
guint n_modes = 1;
#ifdef HAVE_NATIVE_BACKEND
if (META_IS_BACKEND_NATIVE (backend))
{
struct libinput_device *libinput_device;
struct libinput_tablet_pad_mode_group *mode_group;
guint n_group;
libinput_device = clutter_evdev_input_device_get_libinput_device (group->pad->device);
n_group = g_list_index (group->pad->groups, group);
mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, n_group);
n_modes = libinput_tablet_pad_mode_group_get_num_modes (mode_group);
}
#endif
return n_modes;
}
gboolean
meta_wayland_tablet_pad_group_has_button (MetaWaylandTabletPadGroup *group,
guint button)
{
MetaBackend *backend = meta_get_backend ();
#ifdef HAVE_NATIVE_BACKEND
if (META_IS_BACKEND_NATIVE (backend))
{
struct libinput_device *libinput_device;
struct libinput_tablet_pad_mode_group *mode_group;
guint n_group;
libinput_device = clutter_evdev_input_device_get_libinput_device (group->pad->device);
n_group = g_list_index (group->pad->groups, group);
mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, n_group);
return libinput_tablet_pad_mode_group_has_button (mode_group, button);
}
else
#endif
{
return g_list_length (group->pad->groups) == 1;
}
}
static void
meta_wayland_tablet_pad_group_send_buttons (MetaWaylandTabletPadGroup *group,
struct wl_resource *resource)
{
struct wl_array buttons;
guint i;
wl_array_init (&buttons);
for (i = 0; i < group->pad->n_buttons; i++)
{
uint32_t *pos;
if (!meta_wayland_tablet_pad_group_has_button (group, i))
continue;
pos = wl_array_add (&buttons, sizeof (*pos));
*pos = i;
}
zwp_tablet_pad_group_v2_send_buttons (resource, &buttons);
wl_array_release (&buttons);
}
void
meta_wayland_tablet_pad_group_notify (MetaWaylandTabletPadGroup *group,
struct wl_resource *resource)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_array buttons;
guint n_modes;
GList *l;
wl_array_init (&buttons);
/* Buttons */
meta_wayland_tablet_pad_group_send_buttons (group, resource);
/* Rings */
for (l = group->rings; l; l = l->next)
{
MetaWaylandTabletPadRing *ring = l->data;
struct wl_resource *ring_resource;
ring_resource = meta_wayland_tablet_pad_ring_create_new_resource (ring,
client,
resource,
0);
zwp_tablet_pad_group_v2_send_ring (resource, ring_resource);
}
/* Strips */
for (l = group->strips; l; l = l->next)
{
MetaWaylandTabletPadStrip *strip = l->data;
struct wl_resource *strip_resource;
strip_resource = meta_wayland_tablet_pad_strip_create_new_resource (strip,
client,
resource,
0);
zwp_tablet_pad_group_v2_send_strip (resource, strip_resource);
}
n_modes = tablet_pad_group_get_n_modes (group);
zwp_tablet_pad_group_v2_send_modes (resource, n_modes);
zwp_tablet_pad_group_v2_send_done (resource);
}
void
meta_wayland_tablet_pad_group_update (MetaWaylandTabletPadGroup *group,
const ClutterEvent *event)
{
switch (event->type)
{
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
if (meta_wayland_tablet_pad_group_is_mode_switch_button (group, event->pad_button.button))
group->current_mode = tablet_pad_group_get_current_mode (group);
break;
default:
break;
}
}
static gboolean
handle_pad_ring_event (MetaWaylandTabletPadGroup *group,
const ClutterEvent *event)
{
MetaWaylandTabletPadRing *ring;
if (event->type != CLUTTER_PAD_RING)
return FALSE;
ring = g_list_nth_data (group->rings, event->pad_ring.ring_number);
if (!ring)
return FALSE;
return meta_wayland_tablet_pad_ring_handle_event (ring, event);
}
static gboolean
handle_pad_strip_event (MetaWaylandTabletPadGroup *group,
const ClutterEvent *event)
{
MetaWaylandTabletPadStrip *strip;
if (event->type != CLUTTER_PAD_STRIP)
return FALSE;
strip = g_list_nth_data (group->strips, event->pad_strip.strip_number);
if (!strip)
return FALSE;
return meta_wayland_tablet_pad_strip_handle_event (strip, event);
}
static void
broadcast_group_mode (MetaWaylandTabletPadGroup *group,
uint32_t time)
{
struct wl_display *display = group->pad->tablet_seat->seat->wl_display;
struct wl_list *l = &group->focus_resource_list;
struct wl_resource *resource;
group->mode_switch_serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
{
zwp_tablet_pad_group_v2_send_mode_switch (resource, time,
group->mode_switch_serial,
group->current_mode);
}
}
static void
broadcast_group_buttons (MetaWaylandTabletPadGroup *group)
{
struct wl_list *l = &group->focus_resource_list;
struct wl_resource *resource;
wl_resource_for_each (resource, l)
{
meta_wayland_tablet_pad_group_send_buttons (group, resource);
}
}
gboolean
meta_wayland_tablet_pad_group_handle_event (MetaWaylandTabletPadGroup *group,
const ClutterEvent *event)
{
switch (clutter_event_type (event))
{
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
if (meta_wayland_tablet_pad_group_is_mode_switch_button (group, event->pad_button.button))
{
if (event->type == CLUTTER_PAD_BUTTON_PRESS)
broadcast_group_mode (group, clutter_event_get_time (event));
return TRUE;
}
else
{
return FALSE;
}
break;
case CLUTTER_PAD_RING:
return handle_pad_ring_event (group, event);
case CLUTTER_PAD_STRIP:
return handle_pad_strip_event (group, event);
default:
return FALSE;
}
}
static void
meta_wayland_tablet_pad_group_update_rings_focus (MetaWaylandTabletPadGroup *group)
{
GList *l;
for (l = group->rings; l; l = l->next)
meta_wayland_tablet_pad_ring_sync_focus (l->data);
}
static void
meta_wayland_tablet_pad_group_update_strips_focus (MetaWaylandTabletPadGroup *group)
{
GList *l;
for (l = group->strips; l; l = l->next)
meta_wayland_tablet_pad_strip_sync_focus (l->data);
}
static void
move_resources (struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
void
meta_wayland_tablet_pad_group_sync_focus (MetaWaylandTabletPadGroup *group)
{
struct wl_list *l = &group->focus_resource_list;
if (!wl_list_empty (l))
{
move_resources (&group->resource_list, &group->focus_resource_list);
}
if (group->pad->focus_surface != NULL)
{
move_resources_for_client (&group->focus_resource_list,
&group->resource_list,
wl_resource_get_client (group->pad->focus_surface->resource));
}
meta_wayland_tablet_pad_group_update_rings_focus (group);
meta_wayland_tablet_pad_group_update_strips_focus (group);
broadcast_group_mode (group, clutter_get_current_event_time ());
broadcast_group_buttons (group);
}
gboolean
meta_wayland_tablet_pad_group_is_mode_switch_button (MetaWaylandTabletPadGroup *group,
guint button)
{
MetaBackend *backend = meta_get_backend ();
#ifdef HAVE_NATIVE_BACKEND
if (META_IS_BACKEND_NATIVE (backend))
{
struct libinput_device *libinput_device;
struct libinput_tablet_pad_mode_group *mode_group;
guint n_group;
libinput_device = clutter_evdev_input_device_get_libinput_device (group->pad->device);
n_group = g_list_index (group->pad->groups, group);
mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, n_group);
return libinput_tablet_pad_mode_group_button_is_toggle (mode_group, button) != 0;
}
else
#endif
return FALSE;
}

View File

@ -0,0 +1,74 @@
/*
* Wayland Support
*
* Copyright (C) 2016 Red Hat
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_WAYLAND_TABLET_PAD_GROUP_H
#define META_WAYLAND_TABLET_PAD_GROUP_H
#include <wayland-server.h>
#include <glib.h>
#include "clutter/clutter.h"
#include "meta-wayland-types.h"
struct _MetaWaylandTabletPadGroup
{
MetaWaylandTabletPad *pad;
GArray *buttons;
uint32_t n_modes;
uint32_t current_mode;
struct wl_list resource_list;
struct wl_list focus_resource_list;
uint32_t mode_switch_serial;
GList *strips;
GList *rings;
};
MetaWaylandTabletPadGroup * meta_wayland_tablet_pad_group_new (MetaWaylandTabletPad *pad);
void meta_wayland_tablet_pad_group_free (MetaWaylandTabletPadGroup *group);
struct wl_resource *
meta_wayland_tablet_pad_group_create_new_resource (MetaWaylandTabletPadGroup *group,
struct wl_client *client,
struct wl_resource *pad_resource,
uint32_t id);
struct wl_resource *
meta_wayland_tablet_pad_group_lookup_resource (MetaWaylandTabletPadGroup *group,
struct wl_client *client);
void meta_wayland_tablet_pad_group_notify (MetaWaylandTabletPadGroup *group,
struct wl_resource *resource);
void meta_wayland_tablet_pad_group_update (MetaWaylandTabletPadGroup *group,
const ClutterEvent *event);
gboolean meta_wayland_tablet_pad_group_handle_event (MetaWaylandTabletPadGroup *group,
const ClutterEvent *event);
void meta_wayland_tablet_pad_group_sync_focus (MetaWaylandTabletPadGroup *group);
gboolean meta_wayland_tablet_pad_group_has_button (MetaWaylandTabletPadGroup *group,
guint button);
gboolean meta_wayland_tablet_pad_group_is_mode_switch_button (MetaWaylandTabletPadGroup *group,
guint button);
#endif /* META_WAYLAND_TABLET_PAD_GROUP_H */

View File

@ -0,0 +1,224 @@
/*
* Wayland Support
*
* Copyright (C) 2016 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>
*/
#define _GNU_SOURCE
#include "config.h"
#include <glib.h>
#include <wayland-server.h>
#include "tablet-unstable-v2-server-protocol.h"
#include "meta-surface-actor-wayland.h"
#include "meta-wayland-private.h"
#include "meta-wayland-tablet-pad.h"
#include "meta-wayland-tablet-pad-group.h"
#include "meta-wayland-tablet-pad-ring.h"
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
MetaWaylandTabletPadRing *
meta_wayland_tablet_pad_ring_new (MetaWaylandTabletPad *pad)
{
MetaWaylandTabletPadRing *ring;
ring = g_slice_new0 (MetaWaylandTabletPadRing);
wl_list_init (&ring->resource_list);
wl_list_init (&ring->focus_resource_list);
ring->pad = pad;
return ring;
}
void
meta_wayland_tablet_pad_ring_free (MetaWaylandTabletPadRing *ring)
{
struct wl_resource *resource, *next;
wl_resource_for_each_safe (resource, next, &ring->resource_list)
{
zwp_tablet_tool_v2_send_removed (resource);
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
g_free (ring->feedback);
g_slice_free (MetaWaylandTabletPadRing, ring);
}
static void
tablet_pad_ring_set_feedback (struct wl_client *client,
struct wl_resource *resource,
const char *str,
uint32_t serial)
{
MetaWaylandTabletPadRing *ring = wl_resource_get_user_data (resource);
if (ring->group->mode_switch_serial != serial)
return;
ring->feedback = g_strdup (str);
}
static void
tablet_pad_ring_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_pad_ring_v2_interface ring_interface = {
tablet_pad_ring_set_feedback,
tablet_pad_ring_destroy,
};
struct wl_resource *
meta_wayland_tablet_pad_ring_create_new_resource (MetaWaylandTabletPadRing *ring,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_pad_ring_v2_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &ring_interface,
ring, unbind_resource);
wl_resource_set_user_data (resource, ring);
wl_list_insert (&ring->resource_list, wl_resource_get_link (resource));
return resource;
}
struct wl_resource *
meta_wayland_tablet_pad_ring_lookup_resource (MetaWaylandTabletPadRing *ring,
struct wl_client *client)
{
struct wl_resource *resource;
resource = wl_resource_find_for_client (&ring->resource_list, client);
if (!resource)
resource = wl_resource_find_for_client (&ring->focus_resource_list, client);
return resource;
}
gboolean
meta_wayland_tablet_pad_ring_handle_event (MetaWaylandTabletPadRing *ring,
const ClutterEvent *event)
{
struct wl_list *l = &ring->focus_resource_list;
enum zwp_tablet_pad_ring_v2_source source;
gboolean source_known = FALSE;
struct wl_resource *resource;
if (wl_list_empty (l))
return FALSE;
if (event->type != CLUTTER_PAD_RING)
return FALSE;
if (event->pad_ring.ring_source == CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER)
{
source = ZWP_TABLET_PAD_RING_V2_SOURCE_FINGER;
source_known = TRUE;
}
wl_resource_for_each (resource, l)
{
gdouble angle = event->pad_ring.angle;
if (source_known)
zwp_tablet_pad_ring_v2_send_source (resource, source);
if (angle >= 0)
zwp_tablet_pad_ring_v2_send_angle (resource,
wl_fixed_from_double (angle));
else
zwp_tablet_pad_ring_v2_send_stop (resource);
zwp_tablet_pad_ring_v2_send_frame (resource,
clutter_event_get_time (event));
}
return TRUE;
}
static void
move_resources (struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
void
meta_wayland_tablet_pad_ring_sync_focus (MetaWaylandTabletPadRing *ring)
{
struct wl_list *l = &ring->focus_resource_list;
g_clear_pointer (&ring->feedback, g_free);
if (!wl_list_empty (l))
{
move_resources (&ring->resource_list, &ring->focus_resource_list);
}
if (ring->pad->focus_surface != NULL)
{
move_resources_for_client (&ring->focus_resource_list,
&ring->resource_list,
wl_resource_get_client (ring->pad->focus_surface->resource));
}
}
void
meta_wayland_tablet_pad_ring_set_group (MetaWaylandTabletPadRing *ring,
MetaWaylandTabletPadGroup *group)
{
/* Group is static, can only be set once */
g_assert (ring->group == NULL);
ring->group = group;
group->rings = g_list_append (group->rings, ring);
}

View File

@ -0,0 +1,63 @@
/*
* Wayland Support
*
* Copyright (C) 2016 Red Hat
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_WAYLAND_TABLET_PAD_RING_H
#define META_WAYLAND_TABLET_PAD_RING_H
#include <wayland-server.h>
#include <glib.h>
#include "meta-wayland-types.h"
#include "meta-cursor-renderer.h"
struct _MetaWaylandTabletPadRing
{
MetaWaylandTabletPad *pad;
MetaWaylandTabletPadGroup *group;
struct wl_list resource_list;
struct wl_list focus_resource_list;
gchar *feedback;
};
MetaWaylandTabletPadRing * meta_wayland_tablet_pad_ring_new (MetaWaylandTabletPad *pad);
void meta_wayland_tablet_pad_ring_free (MetaWaylandTabletPadRing *ring);
void meta_wayland_tablet_pad_ring_set_group (MetaWaylandTabletPadRing *ring,
MetaWaylandTabletPadGroup *group);
struct wl_resource *
meta_wayland_tablet_pad_ring_create_new_resource (MetaWaylandTabletPadRing *ring,
struct wl_client *client,
struct wl_resource *pad_resource,
uint32_t id);
struct wl_resource *
meta_wayland_tablet_pad_ring_lookup_resource (MetaWaylandTabletPadRing *ring,
struct wl_client *client);
gboolean meta_wayland_tablet_pad_ring_handle_event (MetaWaylandTabletPadRing *ring,
const ClutterEvent *event);
void meta_wayland_tablet_pad_ring_sync_focus (MetaWaylandTabletPadRing *ring);
#endif /* META_WAYLAND_TABLET_PAD_RING_H */

View File

@ -0,0 +1,223 @@
/*
* Wayland Support
*
* Copyright (C) 2016 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>
*/
#define _GNU_SOURCE
#include "config.h"
#include <glib.h>
#include <wayland-server.h>
#include "tablet-unstable-v2-server-protocol.h"
#include "meta-surface-actor-wayland.h"
#include "meta-wayland-private.h"
#include "meta-wayland-tablet-pad.h"
#include "meta-wayland-tablet-pad-group.h"
#include "meta-wayland-tablet-pad-strip.h"
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
MetaWaylandTabletPadStrip *
meta_wayland_tablet_pad_strip_new (MetaWaylandTabletPad *pad)
{
MetaWaylandTabletPadStrip *strip;
strip = g_slice_new0 (MetaWaylandTabletPadStrip);
wl_list_init (&strip->resource_list);
wl_list_init (&strip->focus_resource_list);
strip->pad = pad;
return strip;
}
void
meta_wayland_tablet_pad_strip_free (MetaWaylandTabletPadStrip *strip)
{
struct wl_resource *resource, *next;
wl_resource_for_each_safe (resource, next, &strip->resource_list)
{
zwp_tablet_tool_v2_send_removed (resource);
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
g_free (strip->feedback);
g_slice_free (MetaWaylandTabletPadStrip, strip);
}
static void
tablet_pad_strip_set_feedback (struct wl_client *client,
struct wl_resource *resource,
const char *str,
uint32_t serial)
{
MetaWaylandTabletPadStrip *strip = wl_resource_get_user_data (resource);
if (strip->group->mode_switch_serial != serial)
return;
strip->feedback = g_strdup (str);
}
static void
tablet_pad_strip_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_pad_strip_v2_interface strip_interface = {
tablet_pad_strip_set_feedback,
tablet_pad_strip_destroy,
};
struct wl_resource *
meta_wayland_tablet_pad_strip_create_new_resource (MetaWaylandTabletPadStrip *strip,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_pad_strip_v2_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &strip_interface,
strip, unbind_resource);
wl_resource_set_user_data (resource, strip);
wl_list_insert (&strip->resource_list, wl_resource_get_link (resource));
return resource;
}
struct wl_resource *
meta_wayland_tablet_pad_strip_lookup_resource (MetaWaylandTabletPadStrip *strip,
struct wl_client *client)
{
struct wl_resource *resource;
resource = wl_resource_find_for_client (&strip->resource_list, client);
if (!resource)
resource = wl_resource_find_for_client (&strip->focus_resource_list, client);
return resource;
}
gboolean
meta_wayland_tablet_pad_strip_handle_event (MetaWaylandTabletPadStrip *strip,
const ClutterEvent *event)
{
struct wl_list *l = &strip->focus_resource_list;
enum zwp_tablet_pad_strip_v2_source source;
gboolean source_known = FALSE;
struct wl_resource *resource;
if (wl_list_empty (l))
return FALSE;
if (event->type != CLUTTER_PAD_STRIP)
return FALSE;
if (event->pad_strip.strip_source == CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER)
{
source = ZWP_TABLET_PAD_STRIP_V2_SOURCE_FINGER;
source_known = TRUE;
}
wl_resource_for_each (resource, l)
{
gdouble value = event->pad_strip.value;
if (source_known)
zwp_tablet_pad_strip_v2_send_source (resource, source);
if (value >= 0)
zwp_tablet_pad_strip_v2_send_position (resource, (uint32_t) (value * 65535));
else
zwp_tablet_pad_strip_v2_send_stop (resource);
zwp_tablet_pad_strip_v2_send_frame (resource,
clutter_event_get_time (event));
}
return TRUE;
}
static void
move_resources (struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
void
meta_wayland_tablet_pad_strip_sync_focus (MetaWaylandTabletPadStrip *strip)
{
struct wl_list *l = &strip->focus_resource_list;
g_clear_pointer (&strip->feedback, g_free);
if (!wl_list_empty (l))
{
move_resources (&strip->resource_list, &strip->focus_resource_list);
}
if (strip->pad->focus_surface != NULL)
{
move_resources_for_client (&strip->focus_resource_list,
&strip->resource_list,
wl_resource_get_client (strip->pad->focus_surface->resource));
}
}
void
meta_wayland_tablet_pad_strip_set_group (MetaWaylandTabletPadStrip *strip,
MetaWaylandTabletPadGroup *group)
{
/* Group is static, can only be set once */
g_assert (strip->group == NULL);
strip->group = group;
group->strips = g_list_append (group->strips, strip);
}

View File

@ -0,0 +1,63 @@
/*
* Wayland Support
*
* Copyright (C) 2016 Red Hat
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_WAYLAND_TABLET_PAD_STRIP_H
#define META_WAYLAND_TABLET_PAD_STRIP_H
#include <wayland-server.h>
#include <glib.h>
#include "meta-wayland-types.h"
#include "meta-cursor-renderer.h"
struct _MetaWaylandTabletPadStrip
{
MetaWaylandTabletPad *pad;
MetaWaylandTabletPadGroup *group;
struct wl_list resource_list;
struct wl_list focus_resource_list;
gchar *feedback;
};
MetaWaylandTabletPadStrip * meta_wayland_tablet_pad_strip_new (MetaWaylandTabletPad *pad);
void meta_wayland_tablet_pad_strip_free (MetaWaylandTabletPadStrip *strip);
void meta_wayland_tablet_pad_strip_set_group (MetaWaylandTabletPadStrip *strip,
MetaWaylandTabletPadGroup *group);
struct wl_resource *
meta_wayland_tablet_pad_strip_create_new_resource (MetaWaylandTabletPadStrip *strip,
struct wl_client *client,
struct wl_resource *pad_resource,
uint32_t id);
struct wl_resource *
meta_wayland_tablet_pad_strip_lookup_resource (MetaWaylandTabletPadStrip *strip,
struct wl_client *client);
gboolean meta_wayland_tablet_pad_strip_handle_event (MetaWaylandTabletPadStrip *strip,
const ClutterEvent *event);
void meta_wayland_tablet_pad_strip_sync_focus (MetaWaylandTabletPadStrip *strip);
#endif /* META_WAYLAND_TABLET_PAD_STRIP_H */

View File

@ -0,0 +1,622 @@
/*
* Wayland Support
*
* Copyright (C) 2016 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>
*/
#define _GNU_SOURCE
#include "config.h"
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <wayland-server.h>
#include "tablet-unstable-v2-server-protocol.h"
#include "backends/meta-input-settings-private.h"
#include "meta-surface-actor-wayland.h"
#include "meta-wayland-private.h"
#include "meta-wayland-tablet-seat.h"
#include "meta-wayland-tablet.h"
#include "meta-wayland-tablet-pad.h"
#include "meta-wayland-tablet-pad-group.h"
#include "meta-wayland-tablet-pad-ring.h"
#include "meta-wayland-tablet-pad-strip.h"
#ifdef HAVE_NATIVE_BACKEND
#include <clutter/evdev/clutter-evdev.h>
#include "backends/native/meta-backend-native.h"
#endif
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static void
pad_handle_focus_surface_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandTabletPad *pad = wl_container_of (listener, pad, focus_surface_listener);
meta_wayland_tablet_pad_set_focus (pad, NULL);
}
static void
group_rings_strips (MetaWaylandTabletPad *pad)
{
gint n_group, n_elem;
GList *g, *l;
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *backend = meta_get_backend ();
struct libinput_device *libinput_device = NULL;
if (META_IS_BACKEND_NATIVE (backend))
libinput_device = clutter_evdev_input_device_get_libinput_device (pad->device);
#endif
for (n_group = 0, g = pad->groups; g; g = g->next)
{
MetaWaylandTabletPadGroup *group = g->data;
#ifdef HAVE_NATIVE_BACKEND
struct libinput_tablet_pad_mode_group *mode_group = NULL;
if (libinput_device)
mode_group = libinput_device_tablet_pad_get_mode_group (libinput_device, n_group);
#endif
for (n_elem = 0, l = pad->rings; l; l = l->next)
{
MetaWaylandTabletPadRing *ring = l->data;
#ifdef HAVE_NATIVE_BACKEND
if (mode_group)
{
if (libinput_tablet_pad_mode_group_has_ring (mode_group, n_elem))
meta_wayland_tablet_pad_ring_set_group (ring, group);
}
else
#else
{
/* Assign everything to the first group */
if (n_group == 0)
meta_wayland_tablet_pad_ring_set_group (ring, group);
}
#endif
n_elem++;
}
for (n_elem = 0, l = pad->strips; l; l = l->next)
{
MetaWaylandTabletPadStrip *strip = l->data;
#ifdef HAVE_NATIVE_BACKEND
if (mode_group)
{
if (libinput_tablet_pad_mode_group_has_strip (mode_group, n_elem))
meta_wayland_tablet_pad_strip_set_group (strip, group);
}
else
#else
{
/* Assign everything to the first group */
if (n_group == 0)
meta_wayland_tablet_pad_strip_set_group (strip, group);
}
#endif
n_elem++;
}
n_group++;
}
}
MetaWaylandTabletPad *
meta_wayland_tablet_pad_new (ClutterInputDevice *device,
MetaWaylandTabletSeat *tablet_seat)
{
MetaBackend *backend = meta_get_backend ();
MetaWaylandTabletPad *pad;
guint n_elems, i;
pad = g_slice_new0 (MetaWaylandTabletPad);
wl_list_init (&pad->resource_list);
wl_list_init (&pad->focus_resource_list);
pad->focus_surface_listener.notify = pad_handle_focus_surface_destroy;
pad->device = device;
pad->tablet_seat = tablet_seat;
pad->feedback = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_free);
#ifdef HAVE_NATIVE_BACKEND
/* Buttons, only can be honored this with the native backend */
if (META_IS_BACKEND_NATIVE (backend))
{
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
pad->n_buttons = libinput_device_tablet_pad_get_num_buttons (libinput_device);
}
#endif
n_elems = clutter_input_device_get_n_mode_groups (pad->device);
for (i = 0; i < n_elems; i++)
{
pad->groups = g_list_prepend (pad->groups,
meta_wayland_tablet_pad_group_new (pad));
}
n_elems = clutter_input_device_get_n_rings (pad->device);
for (i = 0; i < n_elems; i++)
{
MetaWaylandTabletPadRing *ring;
ring = meta_wayland_tablet_pad_ring_new (pad);
pad->rings = g_list_prepend (pad->rings, ring);
}
n_elems = clutter_input_device_get_n_strips (pad->device);
for (i = 0; i < n_elems; i++)
{
MetaWaylandTabletPadStrip *strip;
strip = meta_wayland_tablet_pad_strip_new (pad);
pad->strips = g_list_prepend (pad->strips, strip);
}
group_rings_strips (pad);
return pad;
}
void
meta_wayland_tablet_pad_free (MetaWaylandTabletPad *pad)
{
struct wl_resource *resource, *next;
GList *l;
meta_wayland_tablet_pad_set_focus (pad, NULL);
wl_resource_for_each_safe (resource, next, &pad->resource_list)
{
zwp_tablet_pad_v2_send_removed (resource);
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
for (l = pad->groups; l; l = l->next)
meta_wayland_tablet_pad_group_free (l->data);
for (l = pad->rings; l; l = l->next)
meta_wayland_tablet_pad_ring_free (l->data);
for (l = pad->strips; l; l = l->next)
meta_wayland_tablet_pad_strip_free (l->data);
g_list_free (pad->groups);
g_list_free (pad->rings);
g_list_free (pad->strips);
g_hash_table_destroy (pad->feedback);
g_slice_free (MetaWaylandTabletPad, pad);
}
static MetaWaylandTabletPadGroup *
tablet_pad_lookup_button_group (MetaWaylandTabletPad *pad,
guint button)
{
GList *l;
for (l = pad->groups; l; l = l->next)
{
MetaWaylandTabletPadGroup *group = l->data;
if (meta_wayland_tablet_pad_group_has_button (group, button))
return group;
}
return NULL;
}
static void
tablet_pad_set_feedback (struct wl_client *client,
struct wl_resource *resource,
uint32_t button,
const char *str,
uint32_t serial)
{
MetaWaylandTabletPad *pad = wl_resource_get_user_data (resource);
MetaWaylandTabletPadGroup *group = tablet_pad_lookup_button_group (pad, button);
MetaInputSettings *input_settings;
if (!group || group->mode_switch_serial != serial)
return;
input_settings = meta_input_settings_get ();
if (input_settings &&
meta_input_settings_is_pad_button_grabbed (input_settings, pad->device, button))
return;
if (meta_wayland_tablet_pad_group_is_mode_switch_button (group, button))
return;
g_hash_table_insert (pad->feedback, GUINT_TO_POINTER (button), g_strdup (str));
}
static void
tablet_pad_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_pad_v2_interface pad_interface = {
tablet_pad_set_feedback,
tablet_pad_destroy,
};
void
meta_wayland_tablet_pad_notify (MetaWaylandTabletPad *pad,
struct wl_resource *resource)
{
struct wl_client *client = wl_resource_get_client (resource);
GList *l;
zwp_tablet_pad_v2_send_path (resource, clutter_input_device_get_device_node (pad->device));
zwp_tablet_pad_v2_send_buttons (resource, pad->n_buttons);
for (l = pad->groups; l; l = l->next)
{
MetaWaylandTabletPadGroup *group = l->data;
struct wl_resource *group_resource;
group_resource = meta_wayland_tablet_pad_group_create_new_resource (group,
client,
resource,
0);
zwp_tablet_pad_v2_send_group (resource, group_resource);
meta_wayland_tablet_pad_group_notify (group, group_resource);
}
zwp_tablet_pad_v2_send_done (resource);
}
struct wl_resource *
meta_wayland_tablet_pad_create_new_resource (MetaWaylandTabletPad *pad,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_pad_v2_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &pad_interface,
pad, unbind_resource);
wl_resource_set_user_data (resource, pad);
wl_list_insert (&pad->resource_list, wl_resource_get_link (resource));
return resource;
}
struct wl_resource *
meta_wayland_tablet_pad_lookup_resource (MetaWaylandTabletPad *pad,
struct wl_client *client)
{
struct wl_resource *resource;
resource = wl_resource_find_for_client (&pad->resource_list, client);
if (!resource)
resource = wl_resource_find_for_client (&pad->focus_resource_list, client);
return resource;
}
static gboolean
handle_pad_button_event (MetaWaylandTabletPad *pad,
const ClutterEvent *event)
{
enum zwp_tablet_pad_v2_button_state button_state;
struct wl_list *l = &pad->focus_resource_list;
struct wl_resource *resource;
if (wl_list_empty (l))
return FALSE;
if (event->type == CLUTTER_PAD_BUTTON_PRESS)
button_state = ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED;
else if (event->type == CLUTTER_PAD_BUTTON_RELEASE)
button_state = ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED;
else
return FALSE;
wl_resource_for_each (resource, l)
{
zwp_tablet_pad_v2_send_button (resource,
clutter_event_get_time (event),
event->pad_button.button, button_state);
}
return TRUE;
}
static void
meta_wayland_tablet_pad_update_action (MetaWaylandTabletPad *pad,
const ClutterEvent *event)
{
MetaInputSettings *input_settings;
ClutterInputDevice *device;
guint button;
button = event->pad_button.button;
device = clutter_event_get_source_device (event);
input_settings = meta_input_settings_get ();
if (!input_settings)
return;
meta_input_settings_handle_pad_button (input_settings, device,
event->type == CLUTTER_PAD_BUTTON_PRESS,
button);
}
static gboolean
meta_wayland_tablet_pad_handle_event_action (MetaWaylandTabletPad *pad,
const ClutterEvent *event)
{
MetaInputSettings *input_settings;
ClutterInputDevice *device;
device = clutter_event_get_source_device (event);
input_settings = meta_input_settings_get ();
if (input_settings &&
meta_input_settings_is_pad_button_grabbed (input_settings, device,
event->pad_button.button))
return TRUE;
return FALSE;
}
gboolean
meta_wayland_tablet_pad_handle_event (MetaWaylandTabletPad *pad,
const ClutterEvent *event)
{
MetaWaylandTabletPadGroup *group;
gboolean handled = FALSE;
guint n_group;
n_group = clutter_event_get_mode_group (event);
group = g_list_nth_data (pad->groups, n_group);
switch (clutter_event_type (event))
{
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
if (group)
handled |= meta_wayland_tablet_pad_group_handle_event (group, event);
handled |= meta_wayland_tablet_pad_handle_event_action (pad, event);
if (handled)
return TRUE;
return handle_pad_button_event (pad, event);
case CLUTTER_PAD_RING:
case CLUTTER_PAD_STRIP:
if (group)
return meta_wayland_tablet_pad_group_handle_event (group, event);
default:
return FALSE;
}
}
static void
move_resources (struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
static void
meta_wayland_tablet_pad_update_groups_focus (MetaWaylandTabletPad *pad)
{
GList *l;
for (l = pad->groups; l; l = l->next)
meta_wayland_tablet_pad_group_sync_focus (l->data);
}
void
meta_wayland_tablet_pad_set_focus (MetaWaylandTabletPad *pad,
MetaWaylandSurface *surface)
{
MetaWaylandTablet *tablet;
if (pad->focus_surface == surface)
return;
g_hash_table_remove_all (pad->feedback);
if (pad->focus_surface != NULL)
{
struct wl_resource *resource;
struct wl_list *l = &pad->focus_resource_list;
if (!wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (pad->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
{
zwp_tablet_pad_v2_send_leave (resource, serial, pad->focus_surface->resource);
}
move_resources (&pad->resource_list, &pad->focus_resource_list);
}
wl_list_remove (&pad->focus_surface_listener.link);
pad->focus_surface = NULL;
}
tablet = meta_wayland_tablet_seat_lookup_paired_tablet (pad->tablet_seat, pad);
if (tablet != NULL && surface != NULL)
{
struct wl_resource *resource;
struct wl_list *l;
pad->focus_surface = surface;
wl_resource_add_destroy_listener (pad->focus_surface->resource, &pad->focus_surface_listener);
move_resources_for_client (&pad->focus_resource_list,
&pad->resource_list,
wl_resource_get_client (pad->focus_surface->resource));
l = &pad->focus_resource_list;
if (!wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (pad->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
struct wl_resource *tablet_resource =
meta_wayland_tablet_lookup_resource (tablet, client);
pad->focus_serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
{
zwp_tablet_pad_v2_send_enter (resource, pad->focus_serial,
tablet_resource,
pad->focus_surface->resource);
}
}
}
meta_wayland_tablet_pad_update_groups_focus (pad);
}
void
meta_wayland_tablet_pad_update (MetaWaylandTabletPad *pad,
const ClutterEvent *event)
{
MetaWaylandTabletPadGroup *group;
guint n_group;
n_group = clutter_event_get_mode_group (event);
group = g_list_nth_data (pad->groups, n_group);
if (group)
meta_wayland_tablet_pad_group_update (group, event);
switch (event->type)
{
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
meta_wayland_tablet_pad_update_action (pad, event);
break;
case CLUTTER_PAD_RING:
case CLUTTER_PAD_STRIP:
default:
break;
}
}
static gchar *
meta_wayland_tablet_pad_label_mode_switch_button (MetaWaylandTabletPad *pad,
guint button)
{
MetaWaylandTabletPadGroup *group;
GList *l;
for (l = pad->groups; l; l = l->next)
{
group = l->data;
if (meta_wayland_tablet_pad_group_is_mode_switch_button (group, button))
return g_strdup_printf (_("Mode Switch: Mode %d"), group->current_mode + 1);
}
return NULL;
}
gchar *
meta_wayland_tablet_pad_get_label (MetaWaylandTabletPad *pad,
MetaPadActionType type,
guint action)
{
const gchar *label = NULL;
gchar *mode_label;
switch (type)
{
case META_PAD_ACTION_BUTTON:
mode_label = meta_wayland_tablet_pad_label_mode_switch_button (pad, action);
if (mode_label)
return mode_label;
label = g_hash_table_lookup (pad->feedback, GUINT_TO_POINTER (action));
break;
case META_PAD_ACTION_RING:
{
MetaWaylandTabletPadRing *ring;
ring = g_list_nth_data (pad->rings, action);
if (ring)
label = ring->feedback;
break;
}
case META_PAD_ACTION_STRIP:
{
MetaWaylandTabletPadStrip *strip;
strip = g_list_nth_data (pad->strips, action);
if (strip)
label = strip->feedback;
break;
}
}
return g_strdup (label);
}

View File

@ -0,0 +1,82 @@
/*
* Wayland Support
*
* Copyright (C) 2016 Red Hat
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_WAYLAND_TABLET_PAD_H
#define META_WAYLAND_TABLET_PAD_H
#include <wayland-server.h>
#include <glib.h>
#include "meta-wayland-types.h"
#include "meta-cursor-renderer.h"
struct _MetaWaylandTabletPad
{
MetaWaylandTabletSeat *tablet_seat;
ClutterInputDevice *device;
struct wl_list resource_list;
struct wl_list focus_resource_list;
MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener;
uint32_t focus_serial;
uint32_t n_buttons;
GList *groups;
GList *rings;
GList *strips;
GHashTable *feedback;
MetaWaylandSurface *focus;
};
MetaWaylandTabletPad * meta_wayland_tablet_pad_new (ClutterInputDevice *device,
MetaWaylandTabletSeat *tablet_seat);
void meta_wayland_tablet_pad_free (MetaWaylandTabletPad *pad);
struct wl_resource *
meta_wayland_tablet_pad_create_new_resource (MetaWaylandTabletPad *pad,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id);
struct wl_resource *
meta_wayland_tablet_pad_lookup_resource (MetaWaylandTabletPad *pad,
struct wl_client *client);
void meta_wayland_tablet_pad_notify (MetaWaylandTabletPad *pad,
struct wl_resource *resource);
void meta_wayland_tablet_pad_update (MetaWaylandTabletPad *pad,
const ClutterEvent *event);
gboolean meta_wayland_tablet_pad_handle_event (MetaWaylandTabletPad *pad,
const ClutterEvent *event);
void meta_wayland_tablet_pad_set_focus (MetaWaylandTabletPad *pad,
MetaWaylandSurface *surface);
gchar * meta_wayland_tablet_pad_get_label (MetaWaylandTabletPad *pad,
MetaPadActionType type,
guint action);
#endif /* META_WAYLAND_TABLET_PAD_H */

View File

@ -28,12 +28,18 @@
#include <glib.h>
#include <wayland-server.h>
#include "tablet-unstable-v1-server-protocol.h"
#include "tablet-unstable-v2-server-protocol.h"
#include "meta-wayland-private.h"
#include "meta-wayland-tablet-seat.h"
#include "meta-wayland-tablet.h"
#include "meta-wayland-tablet-tool.h"
#include "meta-wayland-tablet-pad.h"
#ifdef HAVE_NATIVE_BACKEND
#include <clutter/evdev/clutter-evdev.h>
#include "backends/native/meta-backend-native.h"
#endif
static void
unbind_resource (struct wl_resource *resource)
@ -55,7 +61,7 @@ notify_tool_added (MetaWaylandTabletSeat *tablet_seat,
if (!tool_resource)
return;
zwp_tablet_seat_v1_send_tool_added (client_resource, tool_resource);
zwp_tablet_seat_v2_send_tool_added (client_resource, tool_resource);
}
static void
@ -82,7 +88,7 @@ notify_tablet_added (MetaWaylandTabletSeat *tablet_seat,
if (!resource)
return;
zwp_tablet_seat_v1_send_tablet_added (client_resource, resource);
zwp_tablet_seat_v2_send_tablet_added (client_resource, resource);
meta_wayland_tablet_notify (tablet, resource);
}
@ -111,6 +117,59 @@ notify_tablets (MetaWaylandTabletSeat *tablet_seat,
notify_tablet_added (tablet_seat, client_resource, device);
}
static void
notify_pad_added (MetaWaylandTabletSeat *tablet_seat,
struct wl_resource *client_resource,
ClutterInputDevice *device)
{
struct wl_resource *resource;
MetaWaylandTabletPad *pad;
struct wl_client *client;
pad = g_hash_table_lookup (tablet_seat->pads, device);
if (!pad)
return;
client = wl_resource_get_client (client_resource);
if (meta_wayland_tablet_pad_lookup_resource (pad, client))
return;
resource = meta_wayland_tablet_pad_create_new_resource (pad, client,
client_resource, 0);
if (!resource)
return;
zwp_tablet_seat_v2_send_pad_added (client_resource, resource);
meta_wayland_tablet_pad_notify (pad, resource);
}
static void
broadcast_pad_added (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
struct wl_resource *resource;
wl_resource_for_each (resource, &tablet_seat->resource_list)
{
notify_pad_added (tablet_seat, resource, device);
}
}
static void
notify_pads (MetaWaylandTabletSeat *tablet_seat,
struct wl_resource *client_resource)
{
ClutterInputDevice *device;
GHashTableIter iter;
g_hash_table_iter_init (&iter, tablet_seat->pads);
while (g_hash_table_iter_next (&iter, (gpointer *) &device, NULL))
notify_pad_added (tablet_seat, client_resource, device);
}
static gboolean
is_tablet_device (ClutterInputDevice *device)
{
@ -127,18 +186,56 @@ is_tablet_device (ClutterInputDevice *device)
device_type == CLUTTER_CURSOR_DEVICE);
}
static gboolean
is_pad_device (ClutterInputDevice *device)
{
ClutterInputDeviceType device_type;
if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER)
return FALSE;
device_type = clutter_input_device_get_device_type (device);
return device_type == CLUTTER_PAD_DEVICE;
}
static void
meta_wayland_tablet_seat_device_added (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
MetaWaylandTablet *tablet;
MetaWaylandSurface *pad_focus = tablet_seat->seat->keyboard.focus_surface;
if (!is_tablet_device (device))
return;
if (is_tablet_device (device))
{
MetaWaylandTablet *tablet;
GList *pads, *l;
tablet = meta_wayland_tablet_new (device, tablet_seat);
g_hash_table_insert (tablet_seat->tablets, device, tablet);
broadcast_tablet_added (tablet_seat, device);
tablet = meta_wayland_tablet_new (device, tablet_seat);
g_hash_table_insert (tablet_seat->tablets, device, tablet);
broadcast_tablet_added (tablet_seat, device);
/* Because the insertion order is undefined, there might be already
* pads that are logically paired to this tablet. Look those up and
* refocus them.
*/
pads = meta_wayland_tablet_seat_lookup_paired_pads (tablet_seat,
tablet);
for (l = pads; l; l = l->next)
meta_wayland_tablet_pad_set_focus (l->data, pad_focus);
g_list_free (pads);
}
else if (is_pad_device (device))
{
MetaWaylandTabletPad *pad;
pad = meta_wayland_tablet_pad_new (device, tablet_seat);
g_hash_table_insert (tablet_seat->pads, device, pad);
broadcast_pad_added (tablet_seat, device);
meta_wayland_tablet_pad_set_focus (pad, pad_focus);
}
}
static void
@ -146,6 +243,7 @@ meta_wayland_tablet_seat_device_removed (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
g_hash_table_remove (tablet_seat->tablets, device);
g_hash_table_remove (tablet_seat->pads, device);
}
static void
@ -155,23 +253,27 @@ tablet_seat_destroy (struct wl_client *client,
wl_resource_destroy (resource);
}
static const struct zwp_tablet_seat_v1_interface tablet_seat_interface = {
static const struct zwp_tablet_seat_v2_interface tablet_seat_interface = {
tablet_seat_destroy
};
MetaWaylandTabletSeat *
meta_wayland_tablet_seat_new (MetaWaylandTabletManager *manager)
meta_wayland_tablet_seat_new (MetaWaylandTabletManager *manager,
MetaWaylandSeat *seat)
{
MetaWaylandTabletSeat *tablet_seat;
const GSList *devices, *l;
tablet_seat = g_slice_new0 (MetaWaylandTabletSeat);
tablet_seat->manager = manager;
tablet_seat->seat = seat;
tablet_seat->device_manager = clutter_device_manager_get_default ();
tablet_seat->tablets = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) meta_wayland_tablet_free);
tablet_seat->tools = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) meta_wayland_tablet_tool_free);
tablet_seat->pads = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) meta_wayland_tablet_pad_free);
wl_list_init (&tablet_seat->resource_list);
g_signal_connect_swapped (tablet_seat->device_manager, "device-added",
@ -204,6 +306,7 @@ meta_wayland_tablet_seat_free (MetaWaylandTabletSeat *tablet_seat)
tablet_seat);
g_hash_table_destroy (tablet_seat->tablets);
g_hash_table_destroy (tablet_seat->tools);
g_hash_table_destroy (tablet_seat->pads);
g_slice_free (MetaWaylandTabletSeat, tablet_seat);
}
@ -215,7 +318,7 @@ meta_wayland_tablet_seat_create_new_resource (MetaWaylandTabletSeat *tablet_seat
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_seat_v1_interface,
resource = wl_resource_create (client, &zwp_tablet_seat_v2_interface,
wl_resource_get_version (manager_resource),
id);
wl_resource_set_implementation (resource, &tablet_seat_interface,
@ -223,8 +326,9 @@ meta_wayland_tablet_seat_create_new_resource (MetaWaylandTabletSeat *tablet_seat
wl_resource_set_user_data (resource, tablet_seat);
wl_list_insert (&tablet_seat->resource_list, wl_resource_get_link (resource));
/* Notify client of all available tablets */
/* Notify client of all available tablets/pads */
notify_tablets (tablet_seat, resource);
notify_pads (tablet_seat, resource);
return resource;
}
@ -250,6 +354,13 @@ meta_wayland_tablet_seat_lookup_tool (MetaWaylandTabletSeat *tablet_seat,
return g_hash_table_lookup (tablet_seat->tools, tool);
}
MetaWaylandTabletPad *
meta_wayland_tablet_seat_lookup_pad (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
return g_hash_table_lookup (tablet_seat->pads, device);
}
static MetaWaylandTabletTool *
meta_wayland_tablet_seat_ensure_tool (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device,
@ -275,15 +386,9 @@ meta_wayland_tablet_seat_update (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device;
ClutterInputDeviceTool *device_tool;
MetaWaylandTabletTool *tool = NULL;
MetaWaylandTabletPad *pad = NULL;
device = clutter_event_get_source_device (event);
device_tool = clutter_event_get_device_tool (event);
if (device && device_tool)
tool = meta_wayland_tablet_seat_ensure_tool (tablet_seat, device, device_tool);
if (!tool)
return;
switch (event->type)
{
@ -292,8 +397,25 @@ meta_wayland_tablet_seat_update (MetaWaylandTabletSeat *tablet_seat,
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
device_tool = clutter_event_get_device_tool (event);
if (device && device_tool)
tool = meta_wayland_tablet_seat_ensure_tool (tablet_seat, device, device_tool);
if (!tool)
return;
meta_wayland_tablet_tool_update (tool, event);
break;
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_RING:
case CLUTTER_PAD_STRIP:
pad = g_hash_table_lookup (tablet_seat->pads, device);
if (!pad)
return;
return meta_wayland_tablet_pad_update (pad, event);
default:
break;
}
@ -305,14 +427,7 @@ meta_wayland_tablet_seat_handle_event (MetaWaylandTabletSeat *tablet_seat,
{
ClutterInputDeviceTool *device_tool;
MetaWaylandTabletTool *tool = NULL;
device_tool = clutter_event_get_device_tool (event);
if (device_tool)
tool = g_hash_table_lookup (tablet_seat->tools, device_tool);
if (!tool)
return CLUTTER_EVENT_PROPAGATE;
MetaWaylandTabletPad *pad = NULL;
switch (event->type)
{
@ -321,8 +436,26 @@ meta_wayland_tablet_seat_handle_event (MetaWaylandTabletSeat *tablet_seat,
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
device_tool = clutter_event_get_device_tool (event);
if (device_tool)
tool = g_hash_table_lookup (tablet_seat->tools, device_tool);
if (!tool)
return CLUTTER_EVENT_PROPAGATE;
meta_wayland_tablet_tool_handle_event (tool, event);
return CLUTTER_EVENT_PROPAGATE;
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_RING:
case CLUTTER_PAD_STRIP:
pad = g_hash_table_lookup (tablet_seat->pads,
clutter_event_get_source_device (event));
if (!pad)
return CLUTTER_EVENT_PROPAGATE;
return meta_wayland_tablet_pad_handle_event (pad, event);
default:
return CLUTTER_EVENT_STOP;
}
@ -340,3 +473,87 @@ meta_wayland_tablet_seat_notify_tool (MetaWaylandTabletSeat *tablet_seat,
if (resource)
notify_tool_added (tablet_seat, resource, tool);
}
static GList *
lookup_grouped_devices (ClutterInputDevice *device,
ClutterInputDeviceType type)
{
struct libinput_device *dev, *libinput_device;
ClutterDeviceManager *device_manager;
const GSList *devices, *l;
GList *group = NULL;
device_manager = clutter_device_manager_get_default ();
devices = clutter_device_manager_peek_devices (device_manager);
dev = clutter_evdev_input_device_get_libinput_device (device);
for (l = devices; l; l = l->next)
{
if (l->data == device)
continue;
if (clutter_input_device_get_device_type (l->data) != type)
continue;
libinput_device = clutter_evdev_input_device_get_libinput_device (l->data);
if (libinput_device_get_device_group (dev) !=
libinput_device_get_device_group (libinput_device))
continue;
group = g_list_prepend (group, l->data);
}
return group;
}
MetaWaylandTablet *
meta_wayland_tablet_seat_lookup_paired_tablet (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandTabletPad *pad)
{
MetaWaylandTablet *tablet;
GList *devices;
devices = lookup_grouped_devices (pad->device, CLUTTER_TABLET_DEVICE);
/* We only accept one device here */
if (!devices || devices->next)
return NULL;
tablet = meta_wayland_tablet_seat_lookup_tablet (pad->tablet_seat,
devices->data);
g_list_free (devices);
return tablet;
}
GList *
meta_wayland_tablet_seat_lookup_paired_pads (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandTablet *tablet)
{
GList *l, *devices, *pads = NULL;
MetaWaylandTabletPad *pad;
devices = lookup_grouped_devices (tablet->device, CLUTTER_PAD_DEVICE);
for (l = devices; l; l = l->next)
{
pad = meta_wayland_tablet_seat_lookup_pad (tablet_seat, l->data);
if (pad)
pads = g_list_prepend (pads, pad);
}
return pads;
}
void
meta_wayland_tablet_seat_set_pad_focus (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandSurface *surface)
{
MetaWaylandTabletPad *pad;
GHashTableIter iter;
g_hash_table_iter_init (&iter, tablet_seat->pads);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &pad))
meta_wayland_tablet_pad_set_focus (pad, surface);
}

View File

@ -31,14 +31,17 @@
struct _MetaWaylandTabletSeat
{
MetaWaylandTabletManager *manager;
MetaWaylandSeat *seat;
ClutterDeviceManager *device_manager;
struct wl_list resource_list;
GHashTable *tablets;
GHashTable *tools;
GHashTable *pads;
};
MetaWaylandTabletSeat *meta_wayland_tablet_seat_new (MetaWaylandTabletManager *tablet_manager);
MetaWaylandTabletSeat *meta_wayland_tablet_seat_new (MetaWaylandTabletManager *tablet_manager,
MetaWaylandSeat *seat);
void meta_wayland_tablet_seat_free (MetaWaylandTabletSeat *tablet_seat);
struct wl_resource *meta_wayland_tablet_seat_create_new_resource (MetaWaylandTabletSeat *tablet_seat,
@ -54,6 +57,9 @@ MetaWaylandTablet *meta_wayland_tablet_seat_lookup_tablet (MetaWayland
MetaWaylandTabletTool *meta_wayland_tablet_seat_lookup_tool (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDeviceTool *tool);
MetaWaylandTabletPad *meta_wayland_tablet_seat_lookup_pad (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device);
void meta_wayland_tablet_seat_update (MetaWaylandTabletSeat *tablet_seat,
const ClutterEvent *event);
gboolean meta_wayland_tablet_seat_handle_event (MetaWaylandTabletSeat *tablet_seat,
@ -63,4 +69,12 @@ void meta_wayland_tablet_seat_notify_tool (MetaWayland
MetaWaylandTabletTool *tool,
struct wl_client *client);
void meta_wayland_tablet_seat_set_pad_focus (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandSurface *surface);
MetaWaylandTablet *meta_wayland_tablet_seat_lookup_paired_tablet (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandTabletPad *pad);
GList *meta_wayland_tablet_seat_lookup_paired_pads (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandTablet *tablet);
#endif /* META_WAYLAND_TABLET_SEAT_H */

View File

@ -29,22 +29,21 @@
#include <clutter/evdev/clutter-evdev.h>
#include <wayland-server.h>
#include "tablet-unstable-v1-server-protocol.h"
#include "tablet-unstable-v2-server-protocol.h"
#include "meta-wayland-private.h"
#include "meta-wayland-surface-role-cursor.h"
#include "meta-wayland-surface-role-tablet-cursor.h"
#include "meta-surface-actor-wayland.h"
#include "meta-wayland-tablet.h"
#include "meta-wayland-tablet-seat.h"
#include "meta-wayland-tablet-tool.h"
#include "backends/meta-input-settings-private.h"
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.h"
#include <linux/input-event-codes.h>
#endif
#define TABLET_AXIS_MAX 65535
#define DEGREES_PRECISION 100 /* wl_tablet_tool.tilt and .rotation define
* angles in hundreths of a degree
*/
static void
unbind_resource (struct wl_resource *resource)
@ -138,23 +137,23 @@ input_device_get_capabilities (ClutterInputDevice *device)
switch (axis)
{
case CLUTTER_INPUT_AXIS_PRESSURE:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE;
capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE;
break;
case CLUTTER_INPUT_AXIS_DISTANCE:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE;
capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE;
break;
case CLUTTER_INPUT_AXIS_XTILT:
case CLUTTER_INPUT_AXIS_YTILT:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_TILT;
capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_TILT;
break;
case CLUTTER_INPUT_AXIS_ROTATION:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION;
capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION;
break;
case CLUTTER_INPUT_AXIS_WHEEL:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_WHEEL;
capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL;
break;
case CLUTTER_INPUT_AXIS_SLIDER:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER;
capabilities |= 1 << ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER;
break;
default:
break;
@ -164,7 +163,7 @@ input_device_get_capabilities (ClutterInputDevice *device)
return capabilities;
}
static enum zwp_tablet_tool_v1_type
static enum zwp_tablet_tool_v2_type
input_device_tool_get_type (ClutterInputDeviceTool *device_tool)
{
ClutterInputDeviceToolType tool_type;
@ -175,19 +174,19 @@ input_device_tool_get_type (ClutterInputDeviceTool *device_tool)
{
case CLUTTER_INPUT_DEVICE_TOOL_NONE:
case CLUTTER_INPUT_DEVICE_TOOL_PEN:
return ZWP_TABLET_TOOL_V1_TYPE_PEN;
return ZWP_TABLET_TOOL_V2_TYPE_PEN;
case CLUTTER_INPUT_DEVICE_TOOL_ERASER:
return ZWP_TABLET_TOOL_V1_TYPE_ERASER;
return ZWP_TABLET_TOOL_V2_TYPE_ERASER;
case CLUTTER_INPUT_DEVICE_TOOL_BRUSH:
return ZWP_TABLET_TOOL_V1_TYPE_BRUSH;
return ZWP_TABLET_TOOL_V2_TYPE_BRUSH;
case CLUTTER_INPUT_DEVICE_TOOL_PENCIL:
return ZWP_TABLET_TOOL_V1_TYPE_PENCIL;
return ZWP_TABLET_TOOL_V2_TYPE_PENCIL;
case CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH:
return ZWP_TABLET_TOOL_V1_TYPE_AIRBRUSH;
return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH;
case CLUTTER_INPUT_DEVICE_TOOL_MOUSE:
return ZWP_TABLET_TOOL_V1_TYPE_MOUSE;
return ZWP_TABLET_TOOL_V2_TYPE_MOUSE;
case CLUTTER_INPUT_DEVICE_TOOL_LENS:
return ZWP_TABLET_TOOL_V1_TYPE_LENS;
return ZWP_TABLET_TOOL_V2_TYPE_LENS;
}
g_assert_not_reached ();
@ -202,44 +201,46 @@ meta_wayland_tablet_tool_notify_capabilities (MetaWaylandTabletTool *tool,
capabilities = input_device_get_capabilities (tool->device);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE))
zwp_tablet_tool_v1_send_capability (resource,
ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE))
zwp_tablet_tool_v1_send_capability (resource,
ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_TILT))
zwp_tablet_tool_v1_send_capability (resource,
ZWP_TABLET_TOOL_V1_CAPABILITY_TILT);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION))
zwp_tablet_tool_v1_send_capability (resource,
ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER))
zwp_tablet_tool_v1_send_capability (resource,
ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_WHEEL))
zwp_tablet_tool_v1_send_capability (resource,
ZWP_TABLET_TOOL_V1_CAPABILITY_WHEEL);
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE))
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE))
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_TILT))
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_TILT);
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION))
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION);
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER))
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER);
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL))
zwp_tablet_tool_v2_send_capability (resource,
ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL);
}
static void
meta_wayland_tablet_tool_notify_details (MetaWaylandTabletTool *tool,
struct wl_resource *resource)
{
guint64 serial;
guint64 serial, id;
zwp_tablet_tool_v1_send_type (resource,
zwp_tablet_tool_v2_send_type (resource,
input_device_tool_get_type (tool->device_tool));
serial = (guint64) clutter_input_device_tool_get_serial (tool->device_tool);
zwp_tablet_tool_v1_send_hardware_serial (resource, (uint32_t) (serial >> 32),
serial = clutter_input_device_tool_get_serial (tool->device_tool);
zwp_tablet_tool_v2_send_hardware_serial (resource, (uint32_t) (serial >> 32),
(uint32_t) (serial & G_MAXUINT32));
id = clutter_input_device_tool_get_id (tool->device_tool);
zwp_tablet_tool_v2_send_hardware_id_wacom (resource, (uint32_t) (id >> 32),
(uint32_t) (id & G_MAXUINT32));
meta_wayland_tablet_tool_notify_capabilities (tool, resource);
/* FIXME: zwp_tablet_tool_v1.hardware_id_wacom missing */
zwp_tablet_tool_v1_send_done (resource);
zwp_tablet_tool_v2_send_done (resource);
}
static void
@ -274,7 +275,7 @@ broadcast_proximity_in (MetaWaylandTabletTool *tool)
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_proximity_in (resource, tool->proximity_serial,
zwp_tablet_tool_v2_send_proximity_in (resource, tool->proximity_serial,
tablet_resource,
tool->focus_surface->resource);
}
@ -287,7 +288,7 @@ broadcast_proximity_out (MetaWaylandTabletTool *tool)
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_proximity_out (resource);
zwp_tablet_tool_v2_send_proximity_out (resource);
}
}
@ -300,7 +301,7 @@ broadcast_frame (MetaWaylandTabletTool *tool,
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_frame (resource, _time);
zwp_tablet_tool_v2_send_frame (resource, _time);
}
}
@ -410,7 +411,7 @@ meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool)
wl_resource_for_each_safe (resource, next, &tool->resource_list)
{
zwp_tablet_tool_v1_send_removed (resource);
zwp_tablet_tool_v2_send_removed (resource);
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
@ -442,7 +443,7 @@ tool_set_cursor (struct wl_client *client,
if (surface &&
!meta_wayland_surface_assign_role (surface,
META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR))
META_TYPE_WAYLAND_SURFACE_ROLE_TABLET_CURSOR))
{
wl_resource_post_error (resource, WL_POINTER_ERROR_ROLE,
"wl_surface@%d already has a different role",
@ -471,7 +472,7 @@ tool_destroy (struct wl_client *client,
wl_resource_destroy (resource);
}
static const struct zwp_tablet_tool_v1_interface tool_interface = {
static const struct zwp_tablet_tool_v2_interface tool_interface = {
tool_set_cursor,
tool_destroy
};
@ -490,7 +491,7 @@ emit_proximity_in (MetaWaylandTabletTool *tool,
tablet_resource = meta_wayland_tablet_lookup_resource (tool->current_tablet,
client);
zwp_tablet_tool_v1_send_proximity_in (resource, tool->proximity_serial,
zwp_tablet_tool_v2_send_proximity_in (resource, tool->proximity_serial,
tablet_resource, tool->focus_surface->resource);
}
@ -502,7 +503,7 @@ meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_tool_v1_interface,
resource = wl_resource_create (client, &zwp_tablet_tool_v2_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &tool_interface,
tool, unbind_resource);
@ -622,7 +623,7 @@ broadcast_motion (MetaWaylandTabletTool *tool,
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_motion (resource, sx, sy);
zwp_tablet_tool_v2_send_motion (resource, sx, sy);
}
}
@ -636,7 +637,7 @@ broadcast_down (MetaWaylandTabletTool *tool,
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_down (resource, tool->down_serial);
zwp_tablet_tool_v2_send_down (resource, tool->down_serial);
}
}
@ -648,7 +649,62 @@ broadcast_up (MetaWaylandTabletTool *tool,
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_up (resource);
zwp_tablet_tool_v2_send_up (resource);
}
}
static guint32
translate_button_action (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
MetaInputSettings *input_settings;
GDesktopStylusButtonAction action;
input_settings = meta_input_settings_get ();
if (input_settings)
{
ClutterInputDevice *device;
device = clutter_event_get_source_device (event);
action = meta_input_settings_get_stylus_button_action (input_settings,
tool->device_tool,
device,
event->button.button);
}
else
{
action = G_DESKTOP_STYLUS_BUTTON_ACTION_DEFAULT;
}
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:
{
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *backend = meta_get_backend ();
if (META_IS_BACKEND_NATIVE (backend))
{
return clutter_evdev_event_get_event_code (event);
}
else
#endif
{
/* We can't do much better here, there's several
* different BTN_ ranges to cover.
*/
return event->button.button;
}
}
}
}
@ -659,28 +715,15 @@ broadcast_button (MetaWaylandTabletTool *tool,
struct wl_resource *resource;
guint32 button;
button = translate_button_action (tool, event);
tool->button_serial = wl_display_next_serial (tool->seat->manager->wl_display);
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *backend = meta_get_backend ();
if (META_IS_BACKEND_NATIVE (backend))
button = clutter_evdev_event_get_event_code (event);
else
#endif
{
/* We can't do much better here, there's several
* different BTN_ ranges to cover.
*/
button = event->button.button;
}
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_button (resource, tool->button_serial, button,
zwp_tablet_tool_v2_send_button (resource, tool->button_serial, button,
event->type == CLUTTER_BUTTON_PRESS ?
ZWP_TABLET_TOOL_V1_BUTTON_STATE_PRESSED :
ZWP_TABLET_TOOL_V1_BUTTON_STATE_RELEASED);
ZWP_TABLET_TOOL_V2_BUTTON_STATE_PRESSED :
ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED);
}
}
@ -699,6 +742,22 @@ broadcast_axis (MetaWaylandTabletTool *tool,
if (!clutter_input_device_get_axis_value (source, event->motion.axes, axis, &val))
return;
if (axis == CLUTTER_INPUT_AXIS_PRESSURE)
{
MetaInputSettings *input_settings;
ClutterInputDevice *device;
input_settings = meta_input_settings_get ();
device = clutter_event_get_source_device (event);
if (input_settings)
{
val = meta_input_settings_translate_tablet_tool_pressure (input_settings,
tool->device_tool,
device, val);
}
}
value = val * TABLET_AXIS_MAX;
wl_resource_for_each (resource, &tool->focus_resource_list)
@ -706,13 +765,13 @@ broadcast_axis (MetaWaylandTabletTool *tool,
switch (axis)
{
case CLUTTER_INPUT_AXIS_PRESSURE:
zwp_tablet_tool_v1_send_pressure (resource, value);
zwp_tablet_tool_v2_send_pressure (resource, value);
break;
case CLUTTER_INPUT_AXIS_DISTANCE:
zwp_tablet_tool_v1_send_distance (resource, value);
zwp_tablet_tool_v2_send_distance (resource, value);
break;
case CLUTTER_INPUT_AXIS_SLIDER:
zwp_tablet_tool_v1_send_slider (resource, value);
zwp_tablet_tool_v2_send_slider (resource, value);
break;
default:
break;
@ -738,9 +797,9 @@ broadcast_tilt (MetaWaylandTabletTool *tool,
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_tilt (resource,
(int32_t) (xtilt * DEGREES_PRECISION),
(int32_t) (ytilt * DEGREES_PRECISION));
zwp_tablet_tool_v2_send_tilt (resource,
wl_fixed_from_double (xtilt),
wl_fixed_from_double (ytilt));
}
}
@ -761,8 +820,8 @@ broadcast_rotation (MetaWaylandTabletTool *tool,
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_rotation (resource,
(int32_t) rotation * DEGREES_PRECISION);
zwp_tablet_tool_v2_send_rotation (resource,
wl_fixed_from_double (rotation));
}
}
@ -779,15 +838,15 @@ broadcast_axes (MetaWaylandTabletTool *tool,
device = clutter_event_get_source_device (event);
capabilities = input_device_get_capabilities (device);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE))
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE))
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_PRESSURE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE))
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE))
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_DISTANCE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_TILT))
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_TILT))
broadcast_tilt (tool, event);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION))
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION))
broadcast_rotation (tool, event);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER))
if (capabilities & (1 << ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER))
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_SLIDER);
/* FIXME: Missing wp_tablet_tool.wheel */

View File

@ -28,7 +28,7 @@
#include <glib.h>
#include <wayland-server.h>
#include "tablet-unstable-v1-server-protocol.h"
#include "tablet-unstable-v2-server-protocol.h"
#include "meta-surface-actor-wayland.h"
#include "meta-wayland-private.h"
@ -61,7 +61,7 @@ meta_wayland_tablet_free (MetaWaylandTablet *tablet)
wl_resource_for_each_safe (resource, next, &tablet->resource_list)
{
zwp_tablet_v1_send_removed (resource);
zwp_tablet_v2_send_removed (resource);
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
@ -76,7 +76,7 @@ tablet_destroy (struct wl_client *client,
wl_resource_destroy (resource);
}
static const struct zwp_tablet_v1_interface tablet_interface = {
static const struct zwp_tablet_v2_interface tablet_interface = {
tablet_destroy
};
@ -87,15 +87,14 @@ meta_wayland_tablet_notify (MetaWaylandTablet *tablet,
ClutterInputDevice *device = tablet->device;
guint vid, pid;
zwp_tablet_v1_send_name (resource, clutter_input_device_get_device_name (device));
zwp_tablet_v2_send_name (resource, clutter_input_device_get_device_name (device));
zwp_tablet_v2_send_path (resource, clutter_input_device_get_device_node (device));
if (sscanf (clutter_input_device_get_vendor_id (device), "%x", &vid) == 1 &&
sscanf (clutter_input_device_get_product_id (device), "%x", &pid) == 1)
zwp_tablet_v1_send_id (resource, vid, pid);
zwp_tablet_v2_send_id (resource, vid, pid);
/* FIXME: zwp_tablet_v1.path missing */
zwp_tablet_v1_send_done (resource);
zwp_tablet_v2_send_done (resource);
}
struct wl_resource *
@ -106,7 +105,7 @@ meta_wayland_tablet_create_new_resource (MetaWaylandTablet *tablet,
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_v1_interface,
resource = wl_resource_create (client, &zwp_tablet_v2_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &tablet_interface,
tablet, unbind_resource);

View File

@ -41,6 +41,10 @@ typedef struct _MetaWaylandTabletManager MetaWaylandTabletManager;
typedef struct _MetaWaylandTabletSeat MetaWaylandTabletSeat;
typedef struct _MetaWaylandTabletTool MetaWaylandTabletTool;
typedef struct _MetaWaylandTablet MetaWaylandTablet;
typedef struct _MetaWaylandTabletPad MetaWaylandTabletPad;
typedef struct _MetaWaylandTabletPadGroup MetaWaylandTabletPadGroup;
typedef struct _MetaWaylandTabletPadStrip MetaWaylandTabletPadStrip;
typedef struct _MetaWaylandTabletPadRing MetaWaylandTabletPadRing;
typedef struct _MetaWaylandBuffer MetaWaylandBuffer;
typedef struct _MetaWaylandRegion MetaWaylandRegion;