Compare commits

...

31 Commits

Author SHA1 Message Date
25bbb4cc40 backends: Allow multiple "SW" cursor overlays on the stage
All the upper layers are prepared for multiple onscreen cursors, but
this. All MetaCursorRenderers created would poke the same internal
MetaOverlay in the stage.

This will lead to multiple cursor renderers resorting to the "SW"
rendering paths (as it can be seen with tablet support) to reuse the
same overlay, thus leading to flickering when a different
MetaCursorRenderer takes over the overlay.

Fix this by allowing per-cursor-renderer overlays, their lifetime
is attached to the cursor renderer, so is expected to be tear down
if the relevant device (eg. tablet) disappears.
2016-05-02 13:49:13 +02:00
3a963d95db wayland: Ensure each MetaWaylandSeat gets its MetaWaylandTabletSeat
Those need to be created in advance in order to handle properly the
events, even on lack of requesting clients.
2016-05-02 12:26:50 +02:00
212a170ae2 core: Update tablet cursors
On wayland, tablets have their standalone pointer, which must be updated
on events from the corresponding device.
2016-05-02 12:26:50 +02:00
17f2b4ea43 wayland: Add methods to update the position of different tools' cursors 2016-05-02 12:26:50 +02:00
4ce4f4eac9 wayland: Implement tool notification
Those must be notified to clients before proximity_in, only if the client
didn't have a resource for this tool previously.
2016-05-02 12:26:50 +02:00
d7b8db3c96 wayland: Let MetaWaylandTabletManager process tablet events
meta_wayland_tablet_manager_update()/handle_event() are called before
the MetaWaylandSeat counterparts. If the event comes from a device
managed by MetaWaylandTabletManager, the event will be exclusively handled
by it.
2016-05-02 12:26:50 +02:00
754a4bf287 wayland: Implement wl_tablet_tool.set_cursor
Each tool has its own MetaCursorRenderer instance, which is created/destroyed
upon proximity, and possibly updated through focus and set_cursor calls in
between.
2016-05-02 12:26:50 +02:00
d46586e383 wayland: Implement wl_tablet_tool device event emission
This takes care of the emission of motion/down/up/button, in addition
to the extra distance/pressure/tilt axes.
2016-05-02 12:26:50 +02:00
38bff73d30 wayland: Add focus management to MetaWaylandTabletTool
Tools can now switch between surfaces, which implies the emission
of wl_tablet_tool.proximity_in/out events.
2016-05-02 12:26:50 +02:00
aaa59ab6a7 wayland: Initialize the MetaWaylandTabletManager 2016-05-02 12:26:50 +02:00
dff045963a wayland: Add MetaWaylandTabletManager
This struct keeps the server side information for the wl_tablet_manager
global resource. It keeps the clients requesting this interface, and
does keep track of the plugged tablet devices, so
wl_tablet_manager.device_added is emitted on the expected clients.
2016-05-02 12:26:50 +02:00
6bbd6d2948 wayland: Add MetaWaylandTabletSeat
This object groups all the tablets/tools pertaining to a given seat.
2016-05-02 12:26:50 +02:00
2ea01aa428 wayland: Add MetaWaylandTabletTool
This struct holds the server-side information of a wl_tablet_tool, which
represents an specific tool of an specific tablet, and is unique as such.
2016-05-02 12:26:50 +02:00
1a31721e57 wayland: Add MetaWaylandTablet
This (very basic at the moment) struct keeps server-side information
for wl_tablet resources.
2016-05-02 12:26:50 +02:00
033c78a7a2 protocol: Generate code for the tablet protocol
This is provided by wayland-protocols
2016-05-02 12:26:50 +02:00
f1afc604d9 backend: Realize cursor on default MetaCursorRenderer paths
The cursor is realized on x11/native subclasses, but not if a base
MetaCursorRenderer is created.
2016-05-02 12:26:50 +02:00
c89edb29f9 wayland: Refactor MetaWaylandSurfaceRoleCursor
Move into a standalone meta-wayland-surface-role-cursor.[ch], and
make generic enough to work for pointe and additional (eg. tablet)
cursors.

Most notably, the sprite is now kept completely internal to the
cursor role, and updates are routed through the given
MetaCursorRenderer (which may be the default one for the pointer,
or something else).

The way cursor updates after cursor surface destruction has also
been reworked, the pointer will just keep track of the last cursor
surface, so older surfaces being destroyed don't trigger pointer
rechecks/updates.
2016-05-02 12:26:50 +02:00
c28fc68df1 wayland: Add MetaWaylandSurface::destroy signal
There's places where it would be convenient to add listeners to this,
so add the signal. The signal is only emitted once during destruction,
it is convenient for the places where we want notifications at a time
the object is still alive, as opposed to weak refs which notify after
the fact.
2016-05-02 12:26:50 +02:00
5774875ab9 evdev: Avoid updating seat pointer position on tablet events 2016-05-02 12:26:50 +02:00
422284e0cd evdev: Implement ClutterInputDevice::update_from_tool
This vfunc pokes the libinput_tool in order to find out the currently
available axes, and updates the device as such.
2016-05-02 12:26:50 +02:00
c72ad23b84 main: Allow updating device axes from the current tool
This way devices are ensured the proper axis status at the time
of processing the events.
2016-05-02 12:26:50 +02:00
d0d343352c evdev: Implement tablet events
Tablet proximity, motion and button events are translated into ClutterEvents,
and the device state is updated accordingly.
2016-05-02 12:26:50 +02:00
feff353081 evdev: Implement ClutterInputDeviceTool
This will be backed by a libinput_tool, the type and serial are
fetched from there.
2016-05-02 12:26:50 +02:00
216298dfad events: Add proximity events
These events will be sent on tool proximity of tablet events.
2016-05-02 12:26:50 +02:00
efd90eb471 event: Add ClutterInputDeviceTool information to clutter events
These can be used to determine the tool that's being in use for a given event
2016-05-02 12:26:50 +02:00
63b1a55283 input-device: Add ClutterInputDeviceTool
This is an unique opaque struct that identifies a given tool of
a given device.
2016-05-02 12:26:50 +02:00
aa0eea9814 enums: Add rotation/slider axes
These will be useful for the tablet tools that have these features.
2016-05-02 12:26:50 +02:00
fe5f12ddb5 evdev: Map LIBINPUT_DEVICE_CAP_TABLET to CLUTTER_TABLET_DEVICE
This is so tablet devices have the correct ClutterInputDeviceType
2016-05-02 12:26:50 +02:00
8110197df4 evdev: Pass axis parameters when notifying absolute motion events
This will be useful for tablet support, NULL is given in the current
callers.
2016-05-02 12:26:50 +02:00
8d290f182a input-device: Disconnect signals on actors where the device has a cursor
Otherwise the signals are left dangling if the device is removed, causing
possible invalid memory accesses afterwards.
2016-05-02 12:26:50 +02:00
9d06421c1f evdev: Use device name rather than sysname
The device name is something more natural, similar to what's seen
in X11, the sysname is rather the event node basename, which may
also vary depending on device insertion/detection time.
2016-05-02 12:26:50 +02:00
40 changed files with 3407 additions and 294 deletions

View File

@ -87,6 +87,7 @@ source_h = \
clutter-group.h \
clutter-image.h \
clutter-input-device.h \
clutter-input-device-tool.h \
clutter-interval.h \
clutter-keyframe-transition.h \
clutter-keysyms.h \
@ -167,6 +168,7 @@ source_c = \
clutter-grid-layout.c \
clutter-image.c \
clutter-input-device.c \
clutter-input-device-tool.c \
clutter-interval.c \
clutter-keyframe-transition.c \
clutter-keysyms-table.c \
@ -459,10 +461,12 @@ evdev_c_priv = \
evdev/clutter-device-manager-evdev.c \
evdev/clutter-input-device-evdev.c \
evdev/clutter-event-evdev.c \
evdev/clutter-input-device-tool-evdev.c \
$(NULL)
evdev_h_priv = \
evdev/clutter-device-manager-evdev.h \
evdev/clutter-input-device-evdev.h \
evdev/clutter-input-device-tool-evdev.h \
$(NULL)
evdev_h = evdev/clutter-evdev.h

View File

@ -132,6 +132,8 @@ struct _ClutterInputDevice
gchar *vendor_id;
gchar *product_id;
GPtrArray *tools;
guint has_cursor : 1;
guint is_enabled : 1;
};
@ -143,6 +145,8 @@ struct _ClutterInputDeviceClass
gboolean (* keycode_to_evdev) (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
void (* update_from_tool) (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
};
/* Platform-dependent interface */
@ -235,6 +239,15 @@ gboolean _clutter_input_device_get_scroll_delta (ClutterInputDev
ClutterScrollDirection *direction_p,
gdouble *delta_p);
ClutterInputDeviceTool * clutter_input_device_lookup_tool (ClutterInputDevice *device,
guint64 serial,
ClutterInputDeviceToolType type);
void clutter_input_device_add_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
void clutter_input_device_update_from_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
G_END_DECLS
#endif /* __CLUTTER_DEVICE_MANAGER_PRIVATE_H__ */

View File

@ -761,6 +761,10 @@ typedef enum { /*< flags prefix=CLUTTER_EVENT >*/
* determined by its phase field; event added in 1.24
* @CLUTTER_TOUCHPAD_SWIPE: A swipe gesture event, the current state is
* determined by its phase field; event added in 1.24
* @CLUTTER_PROXIMITY_IN: A tool entered in proximity to a tablet;
* event added in 1.28
* @CLUTTER_PROXIMITY_OUT: A tool left from the proximity area of a tablet;
* event added in 1.28
* @CLUTTER_EVENT_LAST: Marks the end of the #ClutterEventType enumeration;
* added in 1.10
*
@ -788,6 +792,8 @@ typedef enum { /*< prefix=CLUTTER >*/
CLUTTER_TOUCH_CANCEL,
CLUTTER_TOUCHPAD_PINCH,
CLUTTER_TOUCHPAD_SWIPE,
CLUTTER_PROXIMITY_IN,
CLUTTER_PROXIMITY_OUT,
CLUTTER_EVENT_LAST /* helper */
} ClutterEventType;
@ -946,6 +952,8 @@ typedef enum {
* @CLUTTER_INPUT_AXIS_YTILT: The tile on the Y axis
* @CLUTTER_INPUT_AXIS_WHEEL: A wheel
* @CLUTTER_INPUT_AXIS_DISTANCE: Distance (Since 1.12)
* @CLUTTER_INPUT_AXIS_ROTATION: Rotation along the z-axis (Since 1.28)
* @CLUTTER_INPUT_AXIS_SLIDER: A slider (Since 1.28)
* @CLUTTER_INPUT_AXIS_LAST: Last value of the enumeration; this value is
* useful when iterating over the enumeration values (Since 1.12)
*
@ -963,6 +971,8 @@ typedef enum {
CLUTTER_INPUT_AXIS_YTILT,
CLUTTER_INPUT_AXIS_WHEEL,
CLUTTER_INPUT_AXIS_DISTANCE,
CLUTTER_INPUT_AXIS_ROTATION,
CLUTTER_INPUT_AXIS_SLIDER,
CLUTTER_INPUT_AXIS_LAST
} ClutterInputAxis;
@ -1484,6 +1494,32 @@ typedef enum {
CLUTTER_SCROLL_FINISHED_VERTICAL = 1 << 1
} ClutterScrollFinishFlags;
/**
* ClutterInputDeviceToolType:
* @CLUTTER_INPUT_DEVICE_TOOL_NONE: No tool
* @CLUTTER_INPUT_DEVICE_TOOL_PEN: The tool is a pen
* @CLUTTER_INPUT_DEVICE_TOOL_ERASER: The tool is an eraser
* @CLUTTER_INPUT_DEVICE_TOOL_BRUSH: The tool is a brush
* @CLUTTER_INPUT_DEVICE_TOOL_PENCIL: The tool is a pencil
* @CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH: The tool is an airbrush
* @CLUTTER_INPUT_DEVICE_TOOL_MOUSE: The tool is a mouse
* @CLUTTER_INPUT_DEVICE_TOOL_LENS: The tool is a lens
*
* Defines the type of tool that a #ClutterInputDeviceTool represents.
*
* Since: 1.28
*/
typedef enum {
CLUTTER_INPUT_DEVICE_TOOL_NONE,
CLUTTER_INPUT_DEVICE_TOOL_PEN,
CLUTTER_INPUT_DEVICE_TOOL_ERASER,
CLUTTER_INPUT_DEVICE_TOOL_BRUSH,
CLUTTER_INPUT_DEVICE_TOOL_PENCIL,
CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH,
CLUTTER_INPUT_DEVICE_TOOL_MOUSE,
CLUTTER_INPUT_DEVICE_TOOL_LENS
} ClutterInputDeviceToolType;
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */

View File

@ -54,6 +54,8 @@ typedef struct _ClutterEventPrivate {
gdouble delta_x;
gdouble delta_y;
ClutterInputDeviceTool *tool;
gpointer platform_data;
ClutterModifierType button_state;
@ -409,6 +411,8 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
clutter_point_init (position, 0.f, 0.f);
break;
@ -477,6 +481,8 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
break;
case CLUTTER_ENTER:
@ -1122,6 +1128,11 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_TOUCHPAD_SWIPE:
/* Rely on priv data for these */
break;
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
event->proximity.device = device;
break;
}
}
@ -1201,11 +1212,64 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_TOUCHPAD_SWIPE:
/* Rely on priv data for these */
break;
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
device = event->proximity.device;
break;
}
return device;
}
/**
* clutter_event_set_device_tool:
* @event: a #ClutterEvent
* @tool: (nullable): a #ClutterInputDeviceTool
*
* Sets the tool in use for this event
*
* Since: 1.28
**/
void
clutter_event_set_device_tool (ClutterEvent *event,
ClutterInputDeviceTool *tool)
{
g_return_if_fail (event != NULL);
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
real_event->tool = tool;
}
}
/**
* clutter_event_get_device_tool:
* @event: a #ClutterEvent
*
* Returns the device tool that originated this event
*
* Returns: (transfer none): The tool of this event
*
* Since: 1.28
**/
ClutterInputDeviceTool *
clutter_event_get_device_tool (const ClutterEvent *event)
{
g_return_val_if_fail (event != NULL, NULL);
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
return real_event->tool;
}
return NULL;
}
/**
* clutter_event_new:
* @type: The type of event.
@ -1269,6 +1333,7 @@ clutter_event_copy (const ClutterEvent *event)
new_real_event->button_state = real_event->button_state;
new_real_event->latched_state = real_event->latched_state;
new_real_event->locked_state = real_event->locked_state;
new_real_event->tool = real_event->tool;
}
device = clutter_event_get_device (event);
@ -1617,6 +1682,8 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
break;
case CLUTTER_SCROLL:

View File

@ -117,6 +117,7 @@ typedef struct _ClutterCrossingEvent ClutterCrossingEvent;
typedef struct _ClutterTouchEvent ClutterTouchEvent;
typedef struct _ClutterTouchpadPinchEvent ClutterTouchpadPinchEvent;
typedef struct _ClutterTouchpadSwipeEvent ClutterTouchpadSwipeEvent;
typedef struct _ClutterProximityEvent ClutterProximityEvent;
/**
* ClutterAnyEvent:
@ -213,6 +214,30 @@ struct _ClutterButtonEvent
ClutterInputDevice *device;
};
/**
* ClutterProximityEvent:
* @type: event type
* @time: event time
* @flags: event flags
* @stage: event source stage
* @source: event source actor
* @device: the device that originated the event. If you want the physical
* device the event originated from, use clutter_event_get_source_device()
*
* Event for tool proximity in tablet devices
*
* Since: 1.28
*/
struct _ClutterProximityEvent
{
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
ClutterInputDevice *device;
};
/**
* ClutterCrossingEvent:
* @type: event type
@ -490,6 +515,7 @@ union _ClutterEvent
ClutterTouchEvent touch;
ClutterTouchpadPinchEvent touchpad_pinch;
ClutterTouchpadSwipeEvent touchpad_swipe;
ClutterProximityEvent proximity;
};
/**
@ -575,6 +601,13 @@ void clutter_event_set_source_device (ClutterEvent
CLUTTER_AVAILABLE_IN_1_6
ClutterInputDevice * clutter_event_get_source_device (const ClutterEvent *event);
CLUTTER_AVAILABLE_IN_ALL
void clutter_event_set_device_tool (ClutterEvent *event,
ClutterInputDeviceTool *tool);
CLUTTER_AVAILABLE_IN_ALL
ClutterInputDeviceTool *clutter_event_get_device_tool (const ClutterEvent *event);
CLUTTER_AVAILABLE_IN_1_8
void clutter_event_set_source (ClutterEvent *event,
ClutterActor *actor);

View File

@ -0,0 +1,172 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2009, 2010, 2011 Intel Corp.
*
* 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>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-input-device-tool.h"
#include "clutter-private.h"
typedef struct _ClutterInputDeviceToolPrivate ClutterInputDeviceToolPrivate;
struct _ClutterInputDeviceToolPrivate
{
ClutterInputDeviceToolType type;
guint64 serial;
};
enum {
PROP_0,
PROP_TYPE,
PROP_SERIAL,
PROP_LAST
};
static GParamSpec *props[PROP_LAST] = { NULL, };
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputDeviceTool, clutter_input_device_tool, G_TYPE_OBJECT)
static void
clutter_input_device_tool_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterInputDeviceTool *tool = CLUTTER_INPUT_DEVICE_TOOL (object);
ClutterInputDeviceToolPrivate *priv;
priv = clutter_input_device_tool_get_instance_private (tool);
switch (prop_id)
{
case PROP_TYPE:
priv->type = g_value_get_enum (value);
break;
case PROP_SERIAL:
priv->serial = g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
clutter_input_device_tool_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterInputDeviceTool *tool = CLUTTER_INPUT_DEVICE_TOOL (object);
ClutterInputDeviceToolPrivate *priv;
priv = clutter_input_device_tool_get_instance_private (tool);
switch (prop_id)
{
case PROP_TYPE:
g_value_set_enum (value, priv->type);
break;
case PROP_SERIAL:
g_value_set_uint64 (value, priv->serial);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
clutter_input_device_tool_class_init (ClutterInputDeviceToolClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = clutter_input_device_tool_set_property;
gobject_class->get_property = clutter_input_device_tool_get_property;
props[PROP_TYPE] =
g_param_spec_enum ("type",
P_("Tool type"),
P_("Tool type"),
CLUTTER_TYPE_INPUT_DEVICE_TOOL_TYPE,
CLUTTER_INPUT_DEVICE_TOOL_NONE,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
props[PROP_SERIAL] =
g_param_spec_uint64 ("serial",
P_("Tool serial"),
P_("Tool serial"),
0, G_MAXUINT64, 0,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, PROP_LAST, props);
}
static void
clutter_input_device_tool_init (ClutterInputDeviceTool *tool)
{
}
/**
* clutter_input_device_tool_get_serial:
* @tool: a #ClutterInputDeviceTool
*
* Gets the serial of this tool, this value can be used to identify a
* physical tool (eg. a tablet pen) across program executions.
*
* Returns: The serial ID for this tool
*
* Since: 1.28
**/
guint
clutter_input_device_tool_get_serial (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->serial;
}
/**
* clutter_input_device_tool_get_tool_type:
* @tool: a #ClutterInputDeviceTool
*
* Gets the tool type of this tool.
*
* Returns: The tool type of this tool
*
* Since: 1.28
**/
ClutterInputDeviceToolType
clutter_input_device_tool_get_tool_type (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->type;
}

View File

@ -0,0 +1,66 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2009, 2010, 2011 Intel Corp.
*
* 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 __CLUTTER_INPUT_DEVICE_TOOL_H__
#define __CLUTTER_INPUT_DEVICE_TOOL_H__
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include <clutter/clutter-types.h>
#include "clutter-enum-types.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_INPUT_DEVICE_TOOL (clutter_input_device_tool_get_type ())
#define CLUTTER_INPUT_DEVICE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_TOOL, ClutterInputDeviceTool))
#define CLUTTER_IS_INPUT_DEVICE_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_TOOL))
#define CLUTTER_INPUT_DEVICE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_INPUT_DEVICE_TOOL, ClutterInputDeviceToolClass))
#define CLUTTER_IS_INPUT_DEVICE_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_INPUT_DEVICE_TOOL))
#define CLUTTER_INPUT_DEVICE_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_INPUT_DEVICE_TOOL, ClutterInputDeviceToolClass))
typedef struct _ClutterInputDeviceToolClass ClutterInputDeviceToolClass;
struct _ClutterInputDeviceTool
{
GObject parent_instance;
};
struct _ClutterInputDeviceToolClass
{
GObjectClass parent_class;
};
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);
CLUTTER_AVAILABLE_IN_ALL
ClutterInputDeviceToolType clutter_input_device_tool_get_tool_type (ClutterInputDeviceTool *tool);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_TOOL_H__ */

View File

@ -45,6 +45,7 @@
#include "clutter-marshal.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-input-device-tool.h"
#include <math.h>
@ -73,7 +74,11 @@ enum
};
static void _clutter_input_device_free_touch_info (gpointer data);
static void on_cursor_actor_destroy (ClutterActor *actor,
ClutterInputDevice *device);
static void on_cursor_actor_reactive_changed (ClutterActor *actor,
GParamSpec *pspec,
ClutterInputDevice *device);
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
@ -103,6 +108,18 @@ clutter_input_device_dispose (GObject *gobject)
g_clear_pointer (&device->scroll_info, g_array_unref);
g_clear_pointer (&device->touch_sequences_info, g_hash_table_unref);
if (device->cursor_actor)
{
g_signal_handlers_disconnect_by_func (device->cursor_actor,
G_CALLBACK (on_cursor_actor_destroy),
device);
g_signal_handlers_disconnect_by_func (device->cursor_actor,
G_CALLBACK (on_cursor_actor_reactive_changed),
device);
_clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
device->cursor_actor = NULL;
}
if (device->inv_touch_sequence_actors)
{
GHashTableIter iter;
@ -110,7 +127,16 @@ clutter_input_device_dispose (GObject *gobject)
g_hash_table_iter_init (&iter, device->inv_touch_sequence_actors);
while (g_hash_table_iter_next (&iter, &key, &value))
g_list_free (value);
{
g_signal_handlers_disconnect_by_func (key,
G_CALLBACK (on_cursor_actor_destroy),
device);
g_signal_handlers_disconnect_by_func (device->cursor_actor,
G_CALLBACK (on_cursor_actor_reactive_changed),
device);
_clutter_actor_set_has_pointer (key, FALSE);
g_list_free (value);
}
g_hash_table_unref (device->inv_touch_sequence_actors);
device->inv_touch_sequence_actors = NULL;
@ -598,12 +624,6 @@ _clutter_input_device_get_actor (ClutterInputDevice *device,
return info->actor;
}
static void on_cursor_actor_destroy (ClutterActor *actor,
ClutterInputDevice *device);
static void on_cursor_actor_reactive_changed (ClutterActor *actor,
GParamSpec *pspec,
ClutterInputDevice *device);
static void
_clutter_input_device_associate_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence,
@ -1992,3 +2012,57 @@ clutter_input_device_get_product_id (ClutterInputDevice *device)
return device->product_id;
}
void
clutter_input_device_add_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
g_return_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER);
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool));
if (!device->tools)
device->tools = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
g_ptr_array_add (device->tools, tool);
}
ClutterInputDeviceTool *
clutter_input_device_lookup_tool (ClutterInputDevice *device,
guint64 serial,
ClutterInputDeviceToolType type)
{
ClutterInputDeviceTool *tool;
guint i;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
g_return_val_if_fail (clutter_input_device_get_device_mode (device) != CLUTTER_INPUT_MODE_MASTER, NULL);
if (!device->tools)
return NULL;
for (i = 0; i < device->tools->len; i++)
{
tool = g_ptr_array_index (device->tools, i);
if (serial == clutter_input_device_tool_get_serial (tool) &&
type == clutter_input_device_tool_get_tool_type (tool))
return tool;
}
return NULL;
}
void
clutter_input_device_update_from_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool)
{
ClutterInputDeviceClass *device_class;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
if (device_class->update_from_tool)
device_class->update_from_tool (device, tool);
}

View File

@ -2487,6 +2487,22 @@ _clutter_process_event_details (ClutterActor *stage,
break;
}
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
clutter_input_device_update_from_tool (clutter_event_get_source_device (event),
clutter_event_get_device_tool (event));
if (_clutter_event_process_filters (event))
break;
if (!clutter_actor_event (stage, event, TRUE))
{
/* and bubbling phase */
clutter_actor_event (stage, event, FALSE);
}
break;
case CLUTTER_STAGE_STATE:
/* fullscreen / focus - forward to stage */
event->any.source = stage;

View File

@ -930,7 +930,9 @@ _clutter_stage_queue_event (ClutterStage *stage,
* event processing function
*/
device = clutter_event_get_device (event);
if (device != NULL)
if (device != NULL &&
event->type != CLUTTER_PROXIMITY_IN &&
event->type != CLUTTER_PROXIMITY_OUT)
{
ClutterModifierType event_state = clutter_event_get_state (event);
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);

View File

@ -92,6 +92,7 @@ typedef struct _ClutterAnimation ClutterAnimation;
typedef struct _ClutterAnimator ClutterAnimator;
typedef struct _ClutterState ClutterState;
typedef struct _ClutterInputDeviceTool ClutterInputDeviceTool;
typedef struct _ClutterInputDevice ClutterInputDevice;
typedef CoglMatrix ClutterMatrix;

View File

@ -71,6 +71,7 @@
#include "clutter-group.h"
#include "clutter-image.h"
#include "clutter-input-device.h"
#include "clutter-input-device-tool.h"
#include "clutter-interval.h"
#include "clutter-keyframe-transition.h"
#include "clutter-keysyms.h"

View File

@ -53,6 +53,7 @@
#include "clutter-backend-private.h"
#include "clutter-evdev.h"
#include "clutter-stage-private.h"
#include "clutter-input-device-tool-evdev.h"
#include "clutter-device-manager-evdev.h"
@ -430,7 +431,8 @@ static ClutterEvent *
new_absolute_motion_event (ClutterInputDevice *input_device,
guint64 time_us,
gfloat x,
gfloat y)
gfloat y,
gdouble *axes)
{
gfloat stage_width, stage_height;
ClutterDeviceManagerEvdev *manager_evdev;
@ -449,7 +451,8 @@ new_absolute_motion_event (ClutterInputDevice *input_device,
event = clutter_event_new (CLUTTER_MOTION);
if (manager_evdev->priv->constrain_callback)
if (manager_evdev->priv->constrain_callback &&
clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
{
manager_evdev->priv->constrain_callback (seat->core_pointer,
us2ms (time_us),
@ -471,13 +474,24 @@ new_absolute_motion_event (ClutterInputDevice *input_device,
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
event->motion.x = x;
event->motion.y = y;
clutter_event_set_device (event, seat->core_pointer);
event->motion.axes = axes;
clutter_event_set_source_device (event, input_device);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, input_device);
}
else
clutter_event_set_device (event, seat->core_pointer);
_clutter_input_device_set_stage (seat->core_pointer, stage);
seat->pointer_x = x;
seat->pointer_y = y;
if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
{
seat->pointer_x = x;
seat->pointer_y = y;
}
return event;
}
@ -485,12 +499,13 @@ new_absolute_motion_event (ClutterInputDevice *input_device,
static void
notify_absolute_motion (ClutterInputDevice *input_device,
guint64 time_us,
gfloat x,
gfloat y)
gfloat x,
gfloat y,
gdouble *axes)
{
ClutterEvent *event;
event = new_absolute_motion_event (input_device, time_us, x, y);
event = new_absolute_motion_event (input_device, time_us, x, y, axes);
queue_event (event);
}
@ -523,7 +538,7 @@ notify_relative_motion (ClutterInputDevice *input_device,
new_y = seat->pointer_y + dy;
time_us = libinput_event_pointer_get_time_usec (pointer_event);
event = new_absolute_motion_event (input_device, time_us, new_x, new_y);
event = new_absolute_motion_event (input_device, time_us, new_x, new_y, NULL);
dx_unaccel = libinput_event_pointer_get_dx_unaccelerated (pointer_event);
dy_unaccel = libinput_event_pointer_get_dy_unaccelerated (pointer_event);
@ -680,20 +695,26 @@ notify_button (ClutterInputDevice *input_device,
switch (button)
{
case BTN_LEFT:
case BTN_TOUCH:
button_nr = CLUTTER_BUTTON_PRIMARY;
break;
case BTN_RIGHT:
case BTN_STYLUS:
button_nr = CLUTTER_BUTTON_SECONDARY;
break;
case BTN_MIDDLE:
case BTN_STYLUS2:
button_nr = CLUTTER_BUTTON_MIDDLE;
break;
default:
/* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */
button_nr = button - (BTN_LEFT - 1) + 4;
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
button_nr = button - BTN_TOOL_PEN + 4;
else
button_nr = button - (BTN_LEFT - 1) + 4;
break;
}
@ -708,25 +729,47 @@ notify_button (ClutterInputDevice *input_device,
else
event = clutter_event_new (CLUTTER_BUTTON_RELEASE);
/* Update the modifiers */
if (state)
seat->button_state |= maskmap[button - BTN_LEFT];
else
seat->button_state &= ~maskmap[button - BTN_LEFT];
if (button_nr < G_N_ELEMENTS (maskmap))
{
/* Update the modifiers */
if (state)
seat->button_state |= maskmap[button_nr - 1];
else
seat->button_state &= ~maskmap[button_nr - 1];
}
_clutter_evdev_event_set_time_usec (event, time_us);
event->button.time = us2ms (time_us);
event->button.stage = CLUTTER_STAGE (stage);
event->button.device = seat->core_pointer;
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
event->button.button = button_nr;
event->button.x = seat->pointer_x;
event->button.y = seat->pointer_y;
clutter_event_set_device (event, seat->core_pointer);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
ClutterPoint point;
clutter_input_device_get_coords (input_device, NULL, &point);
event->button.x = point.x;
event->button.y = point.y;
}
else
{
event->button.x = seat->pointer_x;
event->button.y = seat->pointer_y;
}
clutter_event_set_source_device (event, input_device);
_clutter_evdev_event_set_event_code (event, button);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, input_device);
}
else
clutter_event_set_device (event, seat->core_pointer);
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
@ -868,6 +911,44 @@ notify_swipe_gesture_event (ClutterInputDevice *input_device,
queue_event (event);
}
static void
notify_proximity (ClutterInputDevice *input_device,
guint64 time_us,
gboolean in)
{
ClutterInputDeviceEvdev *device_evdev;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterEvent *event = NULL;
/* 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;
device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
seat = _clutter_input_device_evdev_get_seat (device_evdev);
if (in)
event = clutter_event_new (CLUTTER_PROXIMITY_IN);
else
event = clutter_event_new (CLUTTER_PROXIMITY_OUT);
_clutter_evdev_event_set_time_usec (event, time_us);
event->proximity.time = us2ms (time_us);
event->proximity.stage = CLUTTER_STAGE (stage);
event->proximity.device = seat->core_pointer;
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
}
static void
dispatch_libinput (ClutterDeviceManagerEvdev *manager_evdev)
{
@ -1430,6 +1511,122 @@ translate_scroll_source (enum libinput_pointer_axis_source source)
}
}
static ClutterInputDeviceToolType
translate_tool_type (struct libinput_tablet_tool *libinput_tool)
{
enum libinput_tablet_tool_type tool;
tool = libinput_tablet_tool_get_type (libinput_tool);
switch (tool)
{
case LIBINPUT_TABLET_TOOL_TYPE_PEN:
return CLUTTER_INPUT_DEVICE_TOOL_PEN;
case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
return CLUTTER_INPUT_DEVICE_TOOL_ERASER;
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
return CLUTTER_INPUT_DEVICE_TOOL_BRUSH;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
return CLUTTER_INPUT_DEVICE_TOOL_PENCIL;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
return CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH;
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
return CLUTTER_INPUT_DEVICE_TOOL_MOUSE;
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
return CLUTTER_INPUT_DEVICE_TOOL_LENS;
default:
return CLUTTER_INPUT_DEVICE_TOOL_NONE;
}
}
static void
input_device_update_tool (ClutterInputDevice *input_device,
struct libinput_tablet_tool *libinput_tool)
{
ClutterInputDeviceEvdev *evdev_device = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
ClutterInputDeviceTool *tool = NULL;
ClutterInputDeviceToolType tool_type;
guint64 tool_serial;
if (libinput_tool)
{
tool_serial = libinput_tablet_tool_get_serial (libinput_tool);
tool_type = translate_tool_type (libinput_tool);
tool = clutter_input_device_lookup_tool (input_device,
tool_serial, tool_type);
if (!tool)
{
tool = clutter_input_device_tool_evdev_new (libinput_tool,
tool_serial, tool_type);
clutter_input_device_add_tool (input_device, tool);
}
}
evdev_device->last_tool = tool;
}
static gdouble *
translate_tablet_axes (struct libinput_event_tablet_tool *tablet_event)
{
GArray *axes = g_array_new (FALSE, FALSE, sizeof (gdouble));
struct libinput_tablet_tool *libinput_tool;
gdouble value;
libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event);
value = libinput_event_tablet_tool_get_x (tablet_event);
g_array_append_val (axes, value);
value = libinput_event_tablet_tool_get_y (tablet_event);
g_array_append_val (axes, value);
if (libinput_tablet_tool_has_distance (libinput_tool))
{
value = libinput_event_tablet_tool_get_distance (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_pressure (libinput_tool))
{
value = libinput_event_tablet_tool_get_pressure (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_tilt (libinput_tool))
{
value = libinput_event_tablet_tool_get_tilt_x (tablet_event);
g_array_append_val (axes, value);
value = libinput_event_tablet_tool_get_tilt_y (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_rotation (libinput_tool))
{
value = libinput_event_tablet_tool_get_rotation (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_slider (libinput_tool))
{
value = libinput_event_tablet_tool_get_slider_position (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_wheel (libinput_tool))
{
value = libinput_event_tablet_tool_get_wheel_delta (tablet_event);
g_array_append_val (axes, value);
}
if (axes->len == 0)
{
g_array_free (axes, TRUE);
return NULL;
}
else
return (gdouble *) g_array_free (axes, FALSE);
}
static gboolean
process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
struct libinput_event *event)
@ -1500,7 +1697,7 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
stage_width);
y = libinput_event_pointer_get_absolute_y_transformed (motion_event,
stage_height);
notify_absolute_motion (device, time_us, x, y);
notify_absolute_motion (device, time_us, x, y, NULL);
break;
}
@ -1809,6 +2006,84 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
time_us, n_fingers, dx, dy);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
{
guint64 time;
double x, y, *axes;
gfloat stage_width, stage_height;
ClutterStage *stage;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
device = libinput_device_get_user_data (libinput_device);
stage = _clutter_input_device_get_stage (device);
if (!stage)
break;
axes = translate_tablet_axes (tablet_event);
if (!axes)
break;
stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage));
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);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
{
guint64 time;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
struct libinput_tablet_tool *libinput_tool = NULL;
enum libinput_tablet_tool_proximity_state state;
state = libinput_event_tablet_tool_get_proximity_state (tablet_event);
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
device = libinput_device_get_user_data (libinput_device);
libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event);
input_device_update_tool (device, libinput_tool);
notify_proximity (device, time, state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
{
guint64 time;
guint32 button_state;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
guint tablet_button;
device = libinput_device_get_user_data (libinput_device);
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
tablet_button = libinput_event_tablet_tool_get_button (tablet_event);
button_state = libinput_event_tablet_tool_get_button_state (tablet_event) ==
LIBINPUT_BUTTON_STATE_PRESSED;
notify_button (device, time, tablet_button, button_state);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
{
guint64 time;
guint32 button_state;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
device = libinput_device_get_user_data (libinput_device);
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
button_state = libinput_event_tablet_tool_get_tip_state (tablet_event) ==
LIBINPUT_TABLET_TOOL_TIP_DOWN;
notify_button (device, time, BTN_TOUCH, button_state);
break;
}
default:
handled = FALSE;
}
@ -2604,5 +2879,5 @@ clutter_evdev_warp_pointer (ClutterInputDevice *pointer_device,
int x,
int y)
{
notify_absolute_motion (pointer_device, ms2us(time_), x, y);
notify_absolute_motion (pointer_device, ms2us(time_), x, y, NULL);
}

View File

@ -30,6 +30,7 @@
#include "clutter/clutter-device-manager-private.h"
#include "clutter-private.h"
#include "clutter-evdev.h"
#include "clutter-input-device-tool-evdev.h"
#include "clutter-input-device-evdev.h"
#include "clutter-device-manager-evdev.h"
@ -71,6 +72,42 @@ clutter_input_device_evdev_keycode_to_evdev (ClutterInputDevice *device,
return TRUE;
}
static void
clutter_input_device_evdev_update_from_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool)
{
ClutterInputDeviceToolEvdev *evdev_tool;
evdev_tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (tool);
g_object_freeze_notify (G_OBJECT (device));
_clutter_input_device_reset_axes (device);
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_X, 0, 0, 0);
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_Y, 0, 0, 0);
if (libinput_tablet_tool_has_distance (evdev_tool->tool))
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_DISTANCE, 0, 1, 0);
if (libinput_tablet_tool_has_pressure (evdev_tool->tool))
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_PRESSURE, 0, 1, 0);
if (libinput_tablet_tool_has_tilt (evdev_tool->tool))
{
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_XTILT, -90, 90, 0);
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_YTILT, -90, 90, 0);
}
if (libinput_tablet_tool_has_rotation (evdev_tool->tool))
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_ROTATION, 0, 360, 0);
if (libinput_tablet_tool_has_slider (evdev_tool->tool))
_clutter_input_device_add_axis (device, CLUTTER_INPUT_AXIS_SLIDER, -1, 1, 0);
g_object_thaw_notify (G_OBJECT (device));
}
static void
clutter_input_device_evdev_class_init (ClutterInputDeviceEvdevClass *klass)
{
@ -78,6 +115,7 @@ clutter_input_device_evdev_class_init (ClutterInputDeviceEvdevClass *klass)
object_class->finalize = clutter_input_device_evdev_finalize;
klass->keycode_to_evdev = clutter_input_device_evdev_keycode_to_evdev;
klass->update_from_tool = clutter_input_device_evdev_update_from_tool;
}
static void
@ -112,7 +150,7 @@ _clutter_input_device_evdev_new (ClutterDeviceManager *manager,
device_id = _clutter_device_manager_evdev_acquire_device_id (manager_evdev);
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_EVDEV,
"id", device_id,
"name", libinput_device_get_sysname (libinput_device),
"name", libinput_device_get_name (libinput_device),
"device-manager", manager,
"device-type", type,
"device-mode", CLUTTER_INPUT_MODE_SLAVE,
@ -203,6 +241,8 @@ _clutter_input_device_evdev_determine_type (struct libinput_device *ldev)
*/
if (libinput_device_config_tap_get_finger_count (ldev) > 0)
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_POINTER))
return CLUTTER_POINTER_DEVICE;
else if (libinput_device_has_capability (ldev, LIBINPUT_DEVICE_CAP_TOUCH))

View File

@ -65,6 +65,7 @@ struct _ClutterInputDeviceEvdev
struct libinput_device *libinput_device;
ClutterSeatEvdev *seat;
ClutterInputDeviceTool *last_tool;
};
GType _clutter_input_device_evdev_get_type (void) G_GNUC_CONST;

View File

@ -0,0 +1,71 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2009, 2010, 2011 Intel Corp.
*
* 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>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-input-device-tool-evdev.h"
G_DEFINE_TYPE (ClutterInputDeviceToolEvdev, clutter_input_device_tool_evdev,
CLUTTER_TYPE_INPUT_DEVICE_TOOL)
static void
clutter_input_device_tool_evdev_finalize (GObject *object)
{
ClutterInputDeviceToolEvdev *tool = CLUTTER_INPUT_DEVICE_TOOL_EVDEV (object);
libinput_tablet_tool_unref (tool->tool);
G_OBJECT_CLASS (clutter_input_device_tool_evdev_parent_class)->finalize (object);
}
static void
clutter_input_device_tool_evdev_class_init (ClutterInputDeviceToolEvdevClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = clutter_input_device_tool_evdev_finalize;
}
static void
clutter_input_device_tool_evdev_init (ClutterInputDeviceToolEvdev *tool)
{
}
ClutterInputDeviceTool *
clutter_input_device_tool_evdev_new (struct libinput_tablet_tool *tool,
guint64 serial,
ClutterInputDeviceToolType type)
{
ClutterInputDeviceToolEvdev *evdev_tool;
evdev_tool = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV,
"type", type,
"serial", serial,
NULL);
evdev_tool->tool = libinput_tablet_tool_ref (tool);
return CLUTTER_INPUT_DEVICE_TOOL (evdev_tool);
}

View File

@ -0,0 +1,77 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2009, 2010, 2011 Intel Corp.
*
* 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 __CLUTTER_INPUT_DEVICE_EVDEV_TOOL_H__
#define __CLUTTER_INPUT_DEVICE_EVDEV_TOOL_H__
#include <libinput.h>
#include <clutter/clutter-input-device-tool.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV (clutter_input_device_tool_evdev_get_type ())
#define CLUTTER_INPUT_DEVICE_TOOL_EVDEV(o) \
(G_TYPE_CHECK_INSTANCE_CAST ((o), \
CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV, ClutterInputDeviceToolEvdev))
#define CLUTTER_IS_INPUT_DEVICE_TOOL_EVDEV(o) \
(G_TYPE_CHECK_INSTANCE_TYPE ((o), \
CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV))
#define CLUTTER_INPUT_DEVICE_TOOL_EVDEV_CLASS(c) \
(G_TYPE_CHECK_CLASS_CAST ((c), \
CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV, ClutterInputDeviceToolEvdevClass))
#define CLUTTER_IS_INPUT_DEVICE_TOOL_EVDEV_CLASS(c) \
(G_TYPE_CHECK_CLASS_TYPE ((c), \
CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV))
#define CLUTTER_INPUT_DEVICE_TOOL_EVDEV_GET_CLASS(o) \
(G_TYPE_INSTANCE_GET_CLASS ((o), \
CLUTTER_TYPE_INPUT_DEVICE_TOOL_EVDEV, ClutterInputDeviceToolEvdevClass))
typedef struct _ClutterInputDeviceToolEvdev ClutterInputDeviceToolEvdev;
typedef struct _ClutterInputDeviceToolEvdevClass ClutterInputDeviceToolEvdevClass;
struct _ClutterInputDeviceToolEvdev
{
ClutterInputDeviceTool parent_instance;
struct libinput_tablet_tool *tool;
};
struct _ClutterInputDeviceToolEvdevClass
{
ClutterInputDeviceToolClass parent_class;
};
GType clutter_input_device_tool_evdev_get_type (void) G_GNUC_CONST;
ClutterInputDeviceTool * clutter_input_device_tool_evdev_new (struct libinput_tablet_tool *tool,
guint64 serial,
ClutterInputDeviceToolType type);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_EVDEV_TOOL_H__ */

View File

@ -62,6 +62,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 \
$(NULL)
endif
@ -292,10 +294,20 @@ libmutter_la_SOURCES += \
wayland/meta-wayland-popup.h \
wayland/meta-wayland-seat.c \
wayland/meta-wayland-seat.h \
wayland/meta-wayland-tablet.c \
wayland/meta-wayland-tablet.h \
wayland/meta-wayland-tablet-manager.c \
wayland/meta-wayland-tablet-manager.h \
wayland/meta-wayland-tablet-seat.c \
wayland/meta-wayland-tablet-seat.h \
wayland/meta-wayland-tablet-tool.c \
wayland/meta-wayland-tablet-tool.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-types.h \
wayland/meta-wayland-versions.h \
wayland/meta-wayland-outputs.c \

View File

@ -40,6 +40,7 @@ struct _MetaCursorRendererPrivate
int current_x, current_y;
MetaCursorSprite *displayed_cursor;
MetaOverlay *stage_overlay;
gboolean handled_by_backend;
};
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
@ -63,24 +64,48 @@ queue_redraw (MetaCursorRenderer *renderer,
if (!stage)
return;
if (!priv->stage_overlay)
priv->stage_overlay = meta_stage_create_cursor_overlay (META_STAGE (stage));
if (cursor_sprite && !priv->handled_by_backend)
texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
else
texture = NULL;
meta_stage_set_cursor (META_STAGE (stage), texture, &rect);
meta_stage_update_cursor_overlay (META_STAGE (stage), priv->stage_overlay,
texture, &rect);
}
static gboolean
meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
if (cursor_sprite)
meta_cursor_sprite_realize_texture (cursor_sprite);
return FALSE;
}
static void
meta_cursor_renderer_finalize (GObject *object)
{
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (object);
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
if (priv->stage_overlay)
meta_stage_remove_cursor_overlay (META_STAGE (stage), priv->stage_overlay);
G_OBJECT_CLASS (meta_cursor_renderer_parent_class)->finalize (object);
}
static void
meta_cursor_renderer_class_init (MetaCursorRendererClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_cursor_renderer_finalize;
klass->update_cursor = meta_cursor_renderer_real_update_cursor;
}

View File

@ -27,7 +27,7 @@
#include <meta/meta-backend.h>
#include <meta/util.h>
typedef struct {
struct _MetaOverlay {
gboolean enabled;
CoglPipeline *pipeline;
@ -36,22 +36,26 @@ typedef struct {
MetaRectangle current_rect;
MetaRectangle previous_rect;
gboolean previous_is_valid;
} MetaOverlay;
};
struct _MetaStagePrivate {
MetaOverlay cursor_overlay;
GList *overlays;
gboolean is_active;
};
typedef struct _MetaStagePrivate MetaStagePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaStage, meta_stage, CLUTTER_TYPE_STAGE);
static void
meta_overlay_init (MetaOverlay *overlay)
static MetaOverlay *
meta_overlay_new ()
{
MetaOverlay *overlay;
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
overlay = g_slice_new0 (MetaOverlay);
overlay->pipeline = cogl_pipeline_new (ctx);
return overlay;
}
static void
@ -59,6 +63,8 @@ meta_overlay_free (MetaOverlay *overlay)
{
if (overlay->pipeline)
cogl_object_unref (overlay->pipeline);
g_slice_free (MetaOverlay, overlay);
}
static void
@ -111,8 +117,15 @@ meta_stage_finalize (GObject *object)
{
MetaStage *stage = META_STAGE (object);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
GList *l = priv->overlays;
meta_overlay_free (&priv->cursor_overlay);
while (l)
{
meta_overlay_free (l->data);
l = g_list_delete_link (l, l);
}
G_OBJECT_CLASS (meta_stage_parent_class)->finalize (object);
}
static void
@ -120,10 +133,12 @@ meta_stage_paint (ClutterActor *actor)
{
MetaStage *stage = META_STAGE (actor);
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
GList *l;
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
meta_overlay_paint (&priv->cursor_overlay);
for (l = priv->overlays; l; l = l->next)
meta_overlay_paint (l->data);
}
static void
@ -166,10 +181,6 @@ meta_stage_class_init (MetaStageClass *klass)
static void
meta_stage_init (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
meta_overlay_init (&priv->cursor_overlay);
clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), FALSE);
}
@ -209,17 +220,43 @@ queue_redraw_for_overlay (MetaStage *stage,
}
}
void
meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect)
MetaOverlay *
meta_stage_create_cursor_overlay (MetaStage *stage)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
MetaOverlay *overlay;
overlay = meta_overlay_new ();
priv->overlays = g_list_prepend (priv->overlays, overlay);
return overlay;
}
void
meta_stage_remove_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay)
{
MetaStagePrivate *priv = meta_stage_get_instance_private (stage);
GList *link;
link = g_list_find (priv->overlays, overlay);
if (!link)
return;
priv->overlays = g_list_delete_link (priv->overlays, link);
meta_overlay_free (overlay);
}
void
meta_stage_update_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay,
CoglTexture *texture,
MetaRectangle *rect)
{
g_assert (meta_is_wayland_compositor () || texture == NULL);
meta_overlay_set (&priv->cursor_overlay, texture, rect);
queue_redraw_for_overlay (stage, &priv->cursor_overlay);
meta_overlay_set (overlay, texture, rect);
queue_redraw_for_overlay (stage, overlay);
}
void

View File

@ -36,6 +36,7 @@ G_BEGIN_DECLS
typedef struct _MetaStage MetaStage;
typedef struct _MetaStageClass MetaStageClass;
typedef struct _MetaOverlay MetaOverlay;
struct _MetaStageClass
{
@ -51,9 +52,14 @@ GType meta_stage_get_type (void) G_GNUC_CONST;
ClutterActor *meta_stage_new (void);
void meta_stage_set_cursor (MetaStage *stage,
CoglTexture *texture,
MetaRectangle *rect);
MetaOverlay *meta_stage_create_cursor_overlay (MetaStage *stage);
void meta_stage_remove_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay);
void meta_stage_update_cursor_overlay (MetaStage *stage,
MetaOverlay *overlay,
CoglTexture *texture,
MetaRectangle *rect);
void meta_stage_set_active (MetaStage *stage,
gboolean is_active);

View File

@ -221,8 +221,20 @@ meta_display_handle_event (MetaDisplay *display,
if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION)
{
meta_cursor_tracker_update_position (meta_cursor_tracker_get_for_screen (NULL),
event->motion.x, event->motion.y);
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
if (meta_wayland_tablet_manager_consumes_event (compositor->tablet_manager, event))
{
meta_wayland_tablet_manager_update_cursor_position (compositor->tablet_manager, event);
}
else
{
MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL);
meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y);
}
display->monitor_cache_invalidated = TRUE;
}

View File

@ -54,6 +54,7 @@
#include "meta-wayland-private.h"
#include "meta-wayland-surface.h"
#include "meta-wayland-buffer.h"
#include "meta-wayland-surface-role-cursor.h"
#include "meta-xwayland.h"
#include "meta-cursor.h"
#include "meta-cursor-tracker-private.h"
@ -73,24 +74,6 @@
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
struct _MetaWaylandSurfaceRoleCursor
{
MetaWaylandSurfaceRole parent;
int hot_x;
int hot_y;
MetaCursorSprite *cursor_sprite;
MetaWaylandBuffer *buffer;
};
G_DEFINE_TYPE (MetaWaylandSurfaceRoleCursor,
meta_wayland_surface_role_cursor,
META_TYPE_WAYLAND_SURFACE_ROLE);
static void
meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer);
static MetaWaylandPointerClient *
meta_wayland_pointer_client_new (void)
{
@ -501,6 +484,12 @@ meta_wayland_pointer_release (MetaWaylandPointer *pointer)
(gpointer) meta_wayland_pointer_on_cursor_changed,
pointer);
if (pointer->cursor_surface && pointer->cursor_surface_destroy_id)
{
g_signal_handler_disconnect (pointer->cursor_surface,
pointer->cursor_surface_destroy_id);
}
meta_wayland_pointer_set_focus (pointer, NULL);
g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
@ -934,7 +923,7 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
*sy = wl_fixed_from_double (yf);
}
static void
void
meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
{
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
@ -948,7 +937,7 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (pointer->cursor_surface->role);
cursor_sprite = cursor_role->cursor_sprite;
cursor_sprite = meta_wayland_surface_role_cursor_get_sprite (cursor_role);
}
meta_cursor_tracker_set_window_cursor (cursor_tracker, cursor_sprite);
@ -960,68 +949,14 @@ meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer)
}
static void
update_cursor_sprite_texture (MetaWaylandSurface *surface)
ensure_update_cursor_surface (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
{
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (meta_get_backend ());
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
MetaCursorSprite *cursor_sprite = cursor_role->cursor_sprite;
MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface);
if (pointer->cursor_surface != surface)
return;
g_return_if_fail (!buffer || buffer->texture);
if (buffer)
{
meta_cursor_sprite_set_texture (cursor_sprite,
buffer->texture,
cursor_role->hot_x * surface->scale,
cursor_role->hot_y * surface->scale);
if (cursor_role->buffer)
{
struct wl_resource *buffer_resource;
g_assert (cursor_role->buffer == buffer);
buffer_resource = buffer->resource;
meta_cursor_renderer_realize_cursor_from_wl_buffer (cursor_renderer,
cursor_sprite,
buffer_resource);
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
}
}
else
{
meta_cursor_sprite_set_texture (cursor_sprite, NULL, 0, 0);
}
if (cursor_sprite == meta_cursor_tracker_get_displayed_cursor (cursor_tracker))
meta_cursor_renderer_force_update (cursor_renderer);
}
static void
cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite,
int x,
int y,
MetaWaylandSurfaceRoleCursor *cursor_role)
{
MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_role);
MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (role);
MetaDisplay *display = meta_get_display ();
MetaScreen *screen = display->screen;
const MetaMonitorInfo *monitor;
if (!meta_xwayland_is_xwayland_surface (surface))
{
monitor = meta_screen_get_monitor_for_point (screen, x, y);
if (monitor)
meta_cursor_sprite_set_texture_scale (cursor_sprite,
(float)monitor->scale / surface->scale);
}
meta_wayland_surface_update_outputs (surface);
pointer->cursor_surface = NULL;
meta_wayland_pointer_update_cursor_surface (pointer);
}
static void
@ -1031,14 +966,28 @@ meta_wayland_pointer_set_cursor_surface (MetaWaylandPointer *pointer,
MetaWaylandSurface *prev_cursor_surface;
prev_cursor_surface = pointer->cursor_surface;
if (prev_cursor_surface == cursor_surface)
return;
pointer->cursor_surface = cursor_surface;
if (prev_cursor_surface != cursor_surface)
if (prev_cursor_surface)
{
if (prev_cursor_surface)
meta_wayland_surface_update_outputs (prev_cursor_surface);
meta_wayland_pointer_update_cursor_surface (pointer);
meta_wayland_surface_update_outputs (prev_cursor_surface);
g_signal_handler_disconnect (prev_cursor_surface,
pointer->cursor_surface_destroy_id);
}
if (cursor_surface)
{
pointer->cursor_surface_destroy_id =
g_signal_connect_swapped (cursor_surface, "destroy",
G_CALLBACK (ensure_update_cursor_surface),
pointer);
}
meta_wayland_pointer_update_cursor_surface (pointer);
}
static void
@ -1072,23 +1021,15 @@ pointer_set_cursor (struct wl_client *client,
if (surface)
{
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (meta_get_backend ());
MetaWaylandSurfaceRoleCursor *cursor_role;
cursor_role = META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
if (!cursor_role->cursor_sprite)
{
cursor_role->cursor_sprite = meta_cursor_sprite_new ();
g_signal_connect_object (cursor_role->cursor_sprite,
"prepare-at",
G_CALLBACK (cursor_sprite_prepare_at),
cursor_role,
0);
}
cursor_role->hot_x = hot_x;
cursor_role->hot_y = hot_y;
update_cursor_sprite_texture (surface);
meta_wayland_surface_role_cursor_set_renderer (cursor_role,
cursor_renderer);
meta_wayland_surface_role_cursor_set_hotspot (cursor_role,
hot_x, hot_y);
}
meta_wayland_pointer_set_cursor_surface (pointer, surface);
@ -1261,136 +1202,3 @@ meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
MetaWaylandSeat *seat = wl_container_of (pointer, seat, pointer);
return seat;
}
static void
cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_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);
meta_wayland_surface_ref_buffer_use_count (surface);
}
meta_wayland_surface_queue_pending_frame_callbacks (surface);
}
static void
cursor_surface_role_pre_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
if (pending->newly_attached && cursor_role->buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
}
}
static void
cursor_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_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)
meta_wayland_surface_ref_buffer_use_count (surface);
}
meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
if (pending->newly_attached)
update_cursor_sprite_texture (surface);
}
static gboolean
cursor_surface_role_is_on_output (MetaWaylandSurfaceRole *role,
MetaMonitorInfo *monitor)
{
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (role);
MetaWaylandPointer *pointer = &surface->compositor->seat->pointer;
MetaCursorTracker *cursor_tracker = meta_cursor_tracker_get_for_screen (NULL);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (meta_get_backend ());
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
MetaCursorSprite *displayed_cursor_sprite;
MetaRectangle rect;
if (surface != pointer->cursor_surface)
return FALSE;
displayed_cursor_sprite =
meta_cursor_tracker_get_displayed_cursor (cursor_tracker);
if (!displayed_cursor_sprite)
return FALSE;
if (cursor_role->cursor_sprite != displayed_cursor_sprite)
return FALSE;
rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
cursor_role->cursor_sprite);
return meta_rectangle_overlap (&rect, &monitor->rect);
}
static void
cursor_surface_role_dispose (GObject *object)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (object);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWaylandPointer *pointer = &compositor->seat->pointer;
if (pointer->cursor_surface == surface)
pointer->cursor_surface = NULL;
meta_wayland_pointer_update_cursor_surface (pointer);
g_clear_object (&cursor_role->cursor_sprite);
if (cursor_role->buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
}
G_OBJECT_CLASS (meta_wayland_surface_role_cursor_parent_class)->dispose (object);
}
static void
meta_wayland_surface_role_cursor_init (MetaWaylandSurfaceRoleCursor *role)
{
}
static void
meta_wayland_surface_role_cursor_class_init (MetaWaylandSurfaceRoleCursorClass *klass)
{
MetaWaylandSurfaceRoleClass *surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
surface_role_class->assigned = cursor_surface_role_assigned;
surface_role_class->pre_commit = cursor_surface_role_pre_commit;
surface_role_class->commit = cursor_surface_role_commit;
surface_role_class->is_on_output = cursor_surface_role_is_on_output;
object_class->dispose = cursor_surface_role_dispose;
}

View File

@ -32,12 +32,6 @@
#include <meta/meta-cursor-tracker.h>
#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);
struct _MetaWaylandPointerGrabInterface
{
void (*focus) (MetaWaylandPointerGrab *grab,
@ -75,6 +69,7 @@ struct _MetaWaylandPointer
guint32 click_serial;
MetaWaylandSurface *cursor_surface;
guint cursor_surface_destroy_id;
MetaWaylandPointerGrab *grab;
MetaWaylandPointerGrab default_grab;
@ -151,4 +146,8 @@ void meta_wayland_relative_pointer_init (MetaWaylandCompositor *compositor);
MetaWaylandSeat *meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer);
void meta_wayland_surface_cursor_update (MetaWaylandSurface *cursor_surface);
void meta_wayland_pointer_update_cursor_surface (MetaWaylandPointer *pointer);
#endif /* META_WAYLAND_POINTER_H */

View File

@ -33,6 +33,7 @@
#include "meta-wayland-surface.h"
#include "meta-wayland-seat.h"
#include "meta-wayland-pointer-gestures.h"
#include "meta-wayland-tablet-manager.h"
typedef struct _MetaXWaylandSelection MetaXWaylandSelection;
@ -69,6 +70,7 @@ struct _MetaWaylandCompositor
MetaXWaylandManager xwayland_manager;
MetaWaylandSeat *seat;
MetaWaylandTabletManager *tablet_manager;
};
#endif /* META_WAYLAND_PRIVATE_H */

View File

@ -205,7 +205,8 @@ meta_wayland_seat_devices_updated (ClutterDeviceManager *device_manager,
}
static MetaWaylandSeat *
meta_wayland_seat_new (struct wl_display *display)
meta_wayland_seat_new (MetaWaylandCompositor *compositor,
struct wl_display *display)
{
MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
ClutterDeviceManager *device_manager;
@ -224,13 +225,16 @@ meta_wayland_seat_new (struct wl_display *display)
wl_global_create (display, &wl_seat_interface, META_WL_SEAT_VERSION, seat, bind_seat);
meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat);
return seat;
}
void
meta_wayland_seat_init (MetaWaylandCompositor *compositor)
{
compositor->seat = meta_wayland_seat_new (compositor->wayland_display);
compositor->seat = meta_wayland_seat_new (compositor,
compositor->wayland_display);
}
void

View File

@ -0,0 +1,281 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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 <cogl/cogl.h>
#include <cogl/cogl-wayland-server.h>
#include "meta-wayland-surface-role-cursor.h"
#include "meta-wayland-buffer.h"
#include "meta-xwayland.h"
#include "screen-private.h"
struct _MetaWaylandSurfaceRoleCursor
{
MetaWaylandSurfaceRole parent;
int hot_x;
int hot_y;
MetaCursorSprite *cursor_sprite;
MetaCursorRenderer *cursor_renderer;
MetaWaylandBuffer *buffer;
};
G_DEFINE_TYPE (MetaWaylandSurfaceRoleCursor,
meta_wayland_surface_role_cursor,
META_TYPE_WAYLAND_SURFACE_ROLE)
static void
update_cursor_sprite_texture (MetaWaylandSurfaceRoleCursor *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;
g_return_if_fail (!buffer || buffer->texture);
if (!cursor_role->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);
if (cursor_role->buffer)
{
struct wl_resource *buffer_resource;
g_assert (cursor_role->buffer == buffer);
buffer_resource = buffer->resource;
meta_cursor_renderer_realize_cursor_from_wl_buffer (cursor_role->cursor_renderer,
cursor_sprite,
buffer_resource);
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
}
}
else
{
meta_cursor_sprite_set_texture (cursor_sprite, NULL, 0, 0);
}
meta_cursor_renderer_force_update (cursor_role->cursor_renderer);
}
static void
cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite,
int x,
int y,
MetaWaylandSurfaceRoleCursor *cursor_role)
{
MetaWaylandSurfaceRole *role = META_WAYLAND_SURFACE_ROLE (cursor_role);
MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (role);
MetaDisplay *display = meta_get_display ();
MetaScreen *screen = display->screen;
const MetaMonitorInfo *monitor;
if (!meta_xwayland_is_xwayland_surface (surface))
{
monitor = meta_screen_get_monitor_for_point (screen, x, y);
if (monitor)
meta_cursor_sprite_set_texture_scale (cursor_sprite,
(float) monitor->scale / surface->scale);
}
meta_wayland_surface_update_outputs (surface);
}
static void
cursor_surface_role_assigned (MetaWaylandSurfaceRole *surface_role)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_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);
meta_wayland_surface_ref_buffer_use_count (surface);
}
meta_wayland_surface_queue_pending_frame_callbacks (surface);
}
static void
cursor_surface_role_pre_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
if (pending->newly_attached && cursor_role->buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
}
}
static void
cursor_surface_role_commit (MetaWaylandSurfaceRole *surface_role,
MetaWaylandPendingState *pending)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface_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)
meta_wayland_surface_ref_buffer_use_count (surface);
}
meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
if (pending->newly_attached)
update_cursor_sprite_texture (META_WAYLAND_SURFACE_ROLE_CURSOR (surface_role));
}
static gboolean
cursor_surface_role_is_on_output (MetaWaylandSurfaceRole *role,
MetaMonitorInfo *monitor)
{
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (role);
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
MetaRectangle rect;
rect = meta_cursor_renderer_calculate_rect (cursor_role->cursor_renderer,
cursor_role->cursor_sprite);
return meta_rectangle_overlap (&rect, &monitor->rect);
}
static void
cursor_surface_role_dispose (GObject *object)
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (object);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object));
g_signal_handlers_disconnect_by_func (cursor_role->cursor_sprite,
cursor_sprite_prepare_at, cursor_role);
g_clear_object (&cursor_role->cursor_renderer);
g_clear_object (&cursor_role->cursor_sprite);
if (cursor_role->buffer)
{
meta_wayland_surface_unref_buffer_use_count (surface);
g_clear_object (&cursor_role->buffer);
}
G_OBJECT_CLASS (meta_wayland_surface_role_cursor_parent_class)->dispose (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,
"prepare-at",
G_CALLBACK (cursor_sprite_prepare_at),
role,
0);
}
static void
meta_wayland_surface_role_cursor_class_init (MetaWaylandSurfaceRoleCursorClass *klass)
{
MetaWaylandSurfaceRoleClass *surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
surface_role_class->assigned = cursor_surface_role_assigned;
surface_role_class->pre_commit = cursor_surface_role_pre_commit;
surface_role_class->commit = cursor_surface_role_commit;
surface_role_class->is_on_output = cursor_surface_role_is_on_output;
object_class->dispose = cursor_surface_role_dispose;
}
MetaCursorSprite *
meta_wayland_surface_role_cursor_get_sprite (MetaWaylandSurfaceRoleCursor *cursor_role)
{
return cursor_role->cursor_sprite;
}
void
meta_wayland_surface_role_cursor_set_hotspot (MetaWaylandSurfaceRoleCursor *cursor_role,
gint hotspot_x,
gint hotspot_y)
{
if (cursor_role->hot_x == hotspot_x &&
cursor_role->hot_y == hotspot_y)
return;
cursor_role->hot_x = hotspot_x;
cursor_role->hot_y = hotspot_y;
update_cursor_sprite_texture (cursor_role);
}
void
meta_wayland_surface_role_cursor_get_hotspot (MetaWaylandSurfaceRoleCursor *cursor_role,
gint *hotspot_x,
gint *hotspot_y)
{
if (hotspot_x)
*hotspot_x = cursor_role->hot_x;
if (hotspot_y)
*hotspot_y = cursor_role->hot_y;
}
void
meta_wayland_surface_role_cursor_set_renderer (MetaWaylandSurfaceRoleCursor *cursor_role,
MetaCursorRenderer *renderer)
{
if (cursor_role->cursor_renderer == renderer)
return;
if (renderer)
g_object_ref (renderer);
if (cursor_role->cursor_renderer)
g_object_unref (cursor_role->cursor_renderer);
cursor_role->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;
}

View File

@ -0,0 +1,47 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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_CURSOR_H
#define META_WAYLAND_SURFACE_ROLE_CURSOR_H
#include "meta-wayland-surface.h"
#include "backends/meta-cursor-renderer.h"
#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);
MetaCursorSprite * meta_wayland_surface_role_cursor_get_sprite (MetaWaylandSurfaceRoleCursor *cursor_role);
void meta_wayland_surface_role_cursor_set_hotspot (MetaWaylandSurfaceRoleCursor *cursor_role,
gint hotspot_x,
gint hotspot_y);
void meta_wayland_surface_role_cursor_get_hotspot (MetaWaylandSurfaceRoleCursor *cursor_role,
gint *hotspot_x,
gint *hotspot_y);
void meta_wayland_surface_role_cursor_set_renderer (MetaWaylandSurfaceRoleCursor *cursor_role,
MetaCursorRenderer *renderer);
MetaCursorRenderer * meta_wayland_surface_role_cursor_get_renderer (MetaWaylandSurfaceRoleCursor *cursor_role);
#endif /* META_WAYLAND_SURFACE_ROLE_CURSOR_H */

View File

@ -137,6 +137,13 @@ G_DEFINE_TYPE (MetaWaylandSurfaceRoleDND,
meta_wayland_surface_role_dnd,
META_TYPE_WAYLAND_SURFACE_ROLE);
enum {
SURFACE_DESTROY,
N_SURFACE_SIGNALS
};
guint surface_signals[N_SURFACE_SIGNALS] = { 0 };
static void
meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role);
@ -2670,6 +2677,20 @@ meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface,
*y = v.y;
}
static void
meta_wayland_surface_dispose (GObject *object)
{
MetaWaylandSurface *surface = META_WAYLAND_SURFACE (object);
if (!surface->destroying)
{
g_signal_emit (object, surface_signals[SURFACE_DESTROY], 0);
surface->destroying = TRUE;
}
G_OBJECT_CLASS (meta_wayland_surface_parent_class)->dispose (object);
}
static void
meta_wayland_surface_init (MetaWaylandSurface *surface)
{
@ -2679,6 +2700,17 @@ meta_wayland_surface_init (MetaWaylandSurface *surface)
static void
meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_wayland_surface_dispose;
surface_signals[SURFACE_DESTROY] =
g_signal_new ("destroy",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void

View File

@ -198,6 +198,7 @@ struct _MetaWaylandSurface
MetaWaylandSerial acked_configure_serial;
gboolean has_set_geometry;
gboolean is_modal;
gboolean destroying;
/* xdg_popup */
struct {

View File

@ -0,0 +1,267 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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-v1-server-protocol.h"
#include "meta-wayland-private.h"
#include "meta-wayland-tablet-manager.h"
#include "meta-wayland-tablet-seat.h"
#include "meta-wayland-tablet-tool.h"
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static gboolean
is_tablet_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_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE ||
device_type == CLUTTER_CURSOR_DEVICE);
}
static void
tablet_manager_get_tablet_seat (struct wl_client *client,
struct wl_resource *resource,
guint32 id,
struct wl_resource *seat_resource)
{
MetaWaylandTabletManager *tablet_manager = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
MetaWaylandTabletSeat *tablet_seat;
tablet_seat = meta_wayland_tablet_manager_ensure_seat (tablet_manager, seat);
meta_wayland_tablet_seat_create_new_resource (tablet_seat, client,
resource, id);
}
static void
tablet_manager_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_manager_v1_interface tablet_manager_interface = {
tablet_manager_get_tablet_seat,
tablet_manager_destroy
};
static void
bind_tablet_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
MetaWaylandCompositor *compositor = data;
MetaWaylandTabletManager *tablet_manager = compositor->tablet_manager;
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_manager_v1_interface,
MIN (version, 1), id);
wl_resource_set_implementation (resource, &tablet_manager_interface,
tablet_manager, unbind_resource);
wl_resource_set_user_data (resource, tablet_manager);
wl_list_insert (&tablet_manager->resource_list,
wl_resource_get_link (resource));
}
static MetaWaylandTabletManager *
meta_wayland_tablet_manager_new (MetaWaylandCompositor *compositor)
{
MetaWaylandTabletManager *tablet_manager;
tablet_manager = g_slice_new0 (MetaWaylandTabletManager);
tablet_manager->compositor = compositor;
tablet_manager->wl_display = compositor->wayland_display;
tablet_manager->seats = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) meta_wayland_tablet_seat_free);
wl_list_init (&tablet_manager->resource_list);
wl_global_create (tablet_manager->wl_display,
&zwp_tablet_manager_v1_interface, 1,
compositor, bind_tablet_manager);
return tablet_manager;
}
void
meta_wayland_tablet_manager_init (MetaWaylandCompositor *compositor)
{
compositor->tablet_manager = meta_wayland_tablet_manager_new (compositor);
}
void
meta_wayland_tablet_manager_free (MetaWaylandTabletManager *tablet_manager)
{
ClutterDeviceManager *device_manager;
device_manager = clutter_device_manager_get_default ();
g_signal_handlers_disconnect_by_data (device_manager, tablet_manager);
g_hash_table_destroy (tablet_manager->seats);
g_slice_free (MetaWaylandTabletManager, tablet_manager);
}
static MetaWaylandTabletSeat *
meta_wayland_tablet_manager_lookup_seat (MetaWaylandTabletManager *manager,
ClutterInputDevice *device)
{
MetaWaylandTabletSeat *tablet_seat;
MetaWaylandSeat *seat;
GHashTableIter iter;
if (!is_tablet_device (device))
return NULL;
g_hash_table_iter_init (&iter, manager->seats);
while (g_hash_table_iter_next (&iter, (gpointer*) &seat, (gpointer*) &tablet_seat))
{
if (meta_wayland_tablet_seat_lookup_tablet (tablet_seat, device))
return tablet_seat;
}
return NULL;
}
gboolean
meta_wayland_tablet_manager_consumes_event (MetaWaylandTabletManager *manager,
const ClutterEvent *event)
{
ClutterInputDevice *device = clutter_event_get_source_device (event);
return meta_wayland_tablet_manager_lookup_seat (manager, device) != NULL;
}
void
meta_wayland_tablet_manager_update (MetaWaylandTabletManager *manager,
const ClutterEvent *event)
{
ClutterInputDevice *device = clutter_event_get_source_device (event);
MetaWaylandTabletSeat *tablet_seat;
tablet_seat = meta_wayland_tablet_manager_lookup_seat (manager, device);
if (!tablet_seat)
return;
switch (event->type)
{
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
meta_wayland_tablet_seat_update (tablet_seat, event);
break;
default:
break;
}
}
gboolean
meta_wayland_tablet_manager_handle_event (MetaWaylandTabletManager *manager,
const ClutterEvent *event)
{
ClutterInputDevice *device = clutter_event_get_source_device (event);
MetaWaylandTabletSeat *tablet_seat;
tablet_seat = meta_wayland_tablet_manager_lookup_seat (manager, device);
if (!tablet_seat)
return CLUTTER_EVENT_PROPAGATE;
switch (event->type)
{
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
return meta_wayland_tablet_seat_handle_event (tablet_seat, event);
default:
return CLUTTER_EVENT_PROPAGATE;
}
}
MetaWaylandTabletSeat *
meta_wayland_tablet_manager_ensure_seat (MetaWaylandTabletManager *manager,
MetaWaylandSeat *seat)
{
MetaWaylandTabletSeat *tablet_seat;
tablet_seat = g_hash_table_lookup (manager->seats, seat);
if (!tablet_seat)
{
tablet_seat = meta_wayland_tablet_seat_new (manager);
g_hash_table_insert (manager->seats, seat, tablet_seat);
}
return tablet_seat;
}
void
meta_wayland_tablet_manager_update_cursor_position (MetaWaylandTabletManager *manager,
const ClutterEvent *event)
{
MetaWaylandTabletSeat *tablet_seat = NULL;
MetaWaylandTabletTool *tool = NULL;
ClutterInputDeviceTool *device_tool;
ClutterInputDevice *device;
device = clutter_event_get_source_device (event);
device_tool = clutter_event_get_device_tool (event);
if (device)
tablet_seat = meta_wayland_tablet_manager_lookup_seat (manager, device);
if (tablet_seat && device_tool)
tool = meta_wayland_tablet_seat_lookup_tool (tablet_seat, device_tool);
if (tool)
{
gfloat new_x, new_y;
clutter_event_get_coords (event, &new_x, &new_y);
meta_wayland_tablet_tool_set_cursor_position (tool, new_x, new_y);
}
}

View File

@ -0,0 +1,57 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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_MANAGER_H
#define META_WAYLAND_TABLET_MANAGER_H
#include <wayland-server.h>
#include <glib.h>
#include "meta-wayland-types.h"
struct _MetaWaylandTabletManager
{
MetaWaylandCompositor *compositor;
struct wl_display *wl_display;
struct wl_list resource_list;
GHashTable *seats;
};
void meta_wayland_tablet_manager_init (MetaWaylandCompositor *compositor);
void meta_wayland_tablet_manager_free (MetaWaylandTabletManager *tablet_manager);
gboolean meta_wayland_tablet_manager_consumes_event (MetaWaylandTabletManager *manager,
const ClutterEvent *event);
void meta_wayland_tablet_manager_update (MetaWaylandTabletManager *manager,
const ClutterEvent *event);
gboolean meta_wayland_tablet_manager_handle_event (MetaWaylandTabletManager *manager,
const ClutterEvent *event);
MetaWaylandTabletSeat *
meta_wayland_tablet_manager_ensure_seat (MetaWaylandTabletManager *manager,
MetaWaylandSeat *seat);
void meta_wayland_tablet_manager_update_cursor_position (MetaWaylandTabletManager *manager,
const ClutterEvent *event);
#endif /* META_WAYLAND_TABLET_MANAGER_H */

View File

@ -0,0 +1,334 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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-v1-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"
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static void
notify_tool_added (MetaWaylandTabletSeat *tablet_seat,
struct wl_resource *client_resource,
MetaWaylandTabletTool *tool)
{
struct wl_resource *tool_resource;
struct wl_client *client;
client = wl_resource_get_client (client_resource);
tool_resource = meta_wayland_tablet_tool_lookup_resource (tool, client);
if (!tool_resource)
return;
zwp_tablet_seat_v1_send_tool_added (client_resource, tool_resource);
}
static void
notify_tablet_added (MetaWaylandTabletSeat *tablet_seat,
struct wl_resource *client_resource,
ClutterInputDevice *device)
{
struct wl_resource *resource;
MetaWaylandTablet *tablet;
struct wl_client *client;
tablet = g_hash_table_lookup (tablet_seat->tablets, device);
if (!tablet)
return;
client = wl_resource_get_client (client_resource);
if (meta_wayland_tablet_lookup_resource (tablet, client))
return;
resource = meta_wayland_tablet_create_new_resource (tablet, client,
client_resource, 0);
if (!resource)
return;
zwp_tablet_seat_v1_send_tablet_added (client_resource, resource);
meta_wayland_tablet_notify (tablet, resource);
}
static void
broadcast_tablet_added (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
struct wl_resource *resource;
wl_resource_for_each (resource, &tablet_seat->resource_list)
{
notify_tablet_added (tablet_seat, resource, device);
}
}
static void
notify_tablets (MetaWaylandTabletSeat *tablet_seat,
struct wl_resource *client_resource)
{
ClutterInputDevice *device;
GHashTableIter iter;
g_hash_table_iter_init (&iter, tablet_seat->tablets);
while (g_hash_table_iter_next (&iter, (gpointer *) &device, NULL))
notify_tablet_added (tablet_seat, client_resource, device);
}
static gboolean
is_tablet_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_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE ||
device_type == CLUTTER_CURSOR_DEVICE);
}
static void
meta_wayland_tablet_seat_device_added (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
MetaWaylandTablet *tablet;
if (!is_tablet_device (device))
return;
tablet = meta_wayland_tablet_new (device, tablet_seat);
g_hash_table_insert (tablet_seat->tablets, device, tablet);
broadcast_tablet_added (tablet_seat, device);
}
static void
meta_wayland_tablet_seat_device_removed (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
g_hash_table_remove (tablet_seat->tablets, device);
}
static void
tablet_seat_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_seat_v1_interface tablet_seat_interface = {
tablet_seat_destroy
};
MetaWaylandTabletSeat *
meta_wayland_tablet_seat_new (MetaWaylandTabletManager *manager)
{
MetaWaylandTabletSeat *tablet_seat;
const GSList *devices, *l;
tablet_seat = g_slice_new0 (MetaWaylandTabletSeat);
tablet_seat->manager = manager;
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);
wl_list_init (&tablet_seat->resource_list);
g_signal_connect_swapped (tablet_seat->device_manager, "device-added",
G_CALLBACK (meta_wayland_tablet_seat_device_added),
tablet_seat);
g_signal_connect_swapped (tablet_seat->device_manager, "device-removed",
G_CALLBACK (meta_wayland_tablet_seat_device_removed),
tablet_seat);
devices = clutter_device_manager_peek_devices (tablet_seat->device_manager);
for (l = devices; l; l = l->next)
meta_wayland_tablet_seat_device_added (tablet_seat, l->data);
return tablet_seat;
}
void
meta_wayland_tablet_seat_free (MetaWaylandTabletSeat *tablet_seat)
{
g_signal_handlers_disconnect_by_data (tablet_seat->device_manager,
tablet_seat);
g_hash_table_destroy (tablet_seat->tablets);
g_hash_table_destroy (tablet_seat->tools);
g_slice_free (MetaWaylandTabletSeat, tablet_seat);
}
struct wl_resource *
meta_wayland_tablet_seat_create_new_resource (MetaWaylandTabletSeat *tablet_seat,
struct wl_client *client,
struct wl_resource *manager_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_seat_v1_interface,
wl_resource_get_version (manager_resource),
id);
wl_resource_set_implementation (resource, &tablet_seat_interface,
tablet_seat, unbind_resource);
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_tablets (tablet_seat, resource);
return resource;
}
struct wl_resource *
meta_wayland_tablet_seat_lookup_resource (MetaWaylandTabletSeat *tablet_seat,
struct wl_client *client)
{
return wl_resource_find_for_client (&tablet_seat->resource_list, client);
}
MetaWaylandTablet *
meta_wayland_tablet_seat_lookup_tablet (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device)
{
return g_hash_table_lookup (tablet_seat->tablets, device);
}
MetaWaylandTabletTool *
meta_wayland_tablet_seat_lookup_tool (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDeviceTool *tool)
{
return g_hash_table_lookup (tablet_seat->tools, tool);
}
static MetaWaylandTabletTool *
meta_wayland_tablet_seat_ensure_tool (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device,
ClutterInputDeviceTool *device_tool)
{
MetaWaylandTabletTool *tool;
tool = g_hash_table_lookup (tablet_seat->tools, device_tool);
if (!tool)
{
tool = meta_wayland_tablet_tool_new (tablet_seat, device, device_tool);
g_hash_table_insert (tablet_seat->tools, device_tool, tool);
}
return tool;
}
void
meta_wayland_tablet_seat_update (MetaWaylandTabletSeat *tablet_seat,
const ClutterEvent *event)
{
ClutterInputDevice *device;
ClutterInputDeviceTool *device_tool;
MetaWaylandTabletTool *tool = 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)
{
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
meta_wayland_tablet_tool_update (tool, event);
break;
default:
break;
}
}
gboolean
meta_wayland_tablet_seat_handle_event (MetaWaylandTabletSeat *tablet_seat,
const ClutterEvent *event)
{
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;
switch (event->type)
{
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_MOTION:
meta_wayland_tablet_tool_handle_event (tool, event);
return CLUTTER_EVENT_PROPAGATE;
default:
return CLUTTER_EVENT_STOP;
}
}
void
meta_wayland_tablet_seat_notify_tool (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandTabletTool *tool,
struct wl_client *client)
{
struct wl_resource *resource;
resource = wl_resource_find_for_client (&tablet_seat->resource_list, client);
if (resource)
notify_tool_added (tablet_seat, resource, tool);
}

View File

@ -0,0 +1,66 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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_SEAT_H
#define META_WAYLAND_TABLET_SEAT_H
#include <wayland-server.h>
#include <glib.h>
#include "meta-wayland-types.h"
struct _MetaWaylandTabletSeat
{
MetaWaylandTabletManager *manager;
ClutterDeviceManager *device_manager;
struct wl_list resource_list;
GHashTable *tablets;
GHashTable *tools;
};
MetaWaylandTabletSeat *meta_wayland_tablet_seat_new (MetaWaylandTabletManager *tablet_manager);
void meta_wayland_tablet_seat_free (MetaWaylandTabletSeat *tablet_seat);
struct wl_resource *meta_wayland_tablet_seat_create_new_resource (MetaWaylandTabletSeat *tablet_seat,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id);
struct wl_resource *meta_wayland_tablet_seat_lookup_resource (MetaWaylandTabletSeat *tablet_seat,
struct wl_client *client);
MetaWaylandTablet *meta_wayland_tablet_seat_lookup_tablet (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDevice *device);
MetaWaylandTabletTool *meta_wayland_tablet_seat_lookup_tool (MetaWaylandTabletSeat *tablet_seat,
ClutterInputDeviceTool *tool);
void meta_wayland_tablet_seat_update (MetaWaylandTabletSeat *tablet_seat,
const ClutterEvent *event);
gboolean meta_wayland_tablet_seat_handle_event (MetaWaylandTabletSeat *tablet_seat,
const ClutterEvent *event);
void meta_wayland_tablet_seat_notify_tool (MetaWaylandTabletSeat *tablet_seat,
MetaWaylandTabletTool *tool,
struct wl_client *client);
#endif /* META_WAYLAND_TABLET_SEAT_H */

View File

@ -0,0 +1,890 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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 <clutter/evdev/clutter-evdev.h>
#include <wayland-server.h>
#include "tablet-unstable-v1-server-protocol.h"
#include "meta-wayland-private.h"
#include "meta-wayland-surface-role-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"
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.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)
{
wl_list_remove (wl_resource_get_link (resource));
}
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_tool_update_cursor_surface (MetaWaylandTabletTool *tool)
{
MetaCursorSprite *cursor = NULL;
if (tool->cursor_renderer == NULL)
return;
if (tool->current && tool->current_tablet)
{
if (tool->cursor_surface &&
meta_wayland_surface_get_buffer (tool->cursor_surface))
{
MetaWaylandSurfaceRoleCursor *cursor_role =
META_WAYLAND_SURFACE_ROLE_CURSOR (tool->cursor_surface->role);
cursor = meta_wayland_surface_role_cursor_get_sprite (cursor_role);
}
else
cursor = NULL;
}
else if (tool->current_tablet)
cursor = meta_cursor_sprite_from_theme (META_CURSOR_CROSSHAIR);
else
cursor = NULL;
meta_cursor_renderer_set_cursor (tool->cursor_renderer, cursor);
}
static void
meta_wayland_tablet_tool_set_cursor_surface (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface)
{
if (tool->cursor_surface == surface)
return;
if (tool->cursor_surface)
wl_list_remove (&tool->cursor_surface_destroy_listener.link);
tool->cursor_surface = surface;
if (tool->cursor_surface)
wl_resource_add_destroy_listener (tool->cursor_surface->resource,
&tool->cursor_surface_destroy_listener);
meta_wayland_tablet_tool_update_cursor_surface (tool);
}
static uint32_t
input_device_get_capabilities (ClutterInputDevice *device)
{
ClutterInputAxis axis;
guint32 capabilities = 0, i;
for (i = 0; i < clutter_input_device_get_n_axes (device); i++)
{
axis = clutter_input_device_get_axis (device, i);
switch (axis)
{
case CLUTTER_INPUT_AXIS_PRESSURE:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE;
break;
case CLUTTER_INPUT_AXIS_DISTANCE:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE;
break;
case CLUTTER_INPUT_AXIS_XTILT:
case CLUTTER_INPUT_AXIS_YTILT:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_TILT;
break;
case CLUTTER_INPUT_AXIS_ROTATION:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION;
break;
case CLUTTER_INPUT_AXIS_WHEEL:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_WHEEL;
break;
case CLUTTER_INPUT_AXIS_SLIDER:
capabilities |= 1 << ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER;
break;
default:
break;
}
}
return capabilities;
}
static enum zwp_tablet_tool_v1_type
input_device_tool_get_type (ClutterInputDeviceTool *device_tool)
{
ClutterInputDeviceToolType tool_type;
tool_type = clutter_input_device_tool_get_tool_type (device_tool);
switch (tool_type)
{
case CLUTTER_INPUT_DEVICE_TOOL_NONE:
case CLUTTER_INPUT_DEVICE_TOOL_PEN:
return ZWP_TABLET_TOOL_V1_TYPE_PEN;
case CLUTTER_INPUT_DEVICE_TOOL_ERASER:
return ZWP_TABLET_TOOL_V1_TYPE_ERASER;
case CLUTTER_INPUT_DEVICE_TOOL_BRUSH:
return ZWP_TABLET_TOOL_V1_TYPE_BRUSH;
case CLUTTER_INPUT_DEVICE_TOOL_PENCIL:
return ZWP_TABLET_TOOL_V1_TYPE_PENCIL;
case CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH:
return ZWP_TABLET_TOOL_V1_TYPE_AIRBRUSH;
case CLUTTER_INPUT_DEVICE_TOOL_MOUSE:
return ZWP_TABLET_TOOL_V1_TYPE_MOUSE;
case CLUTTER_INPUT_DEVICE_TOOL_LENS:
return ZWP_TABLET_TOOL_V1_TYPE_LENS;
}
g_assert_not_reached ();
return 0;
}
static void
meta_wayland_tablet_tool_notify_capabilities (MetaWaylandTabletTool *tool,
struct wl_resource *resource)
{
uint32_t capabilities;
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);
}
static void
meta_wayland_tablet_tool_notify_details (MetaWaylandTabletTool *tool,
struct wl_resource *resource)
{
guint64 serial;
zwp_tablet_tool_v1_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),
(uint32_t) (serial & 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);
}
static void
meta_wayland_tablet_tool_ensure_resource (MetaWaylandTabletTool *tool,
struct wl_client *client)
{
struct wl_resource *seat_resource, *tool_resource;
seat_resource = meta_wayland_tablet_seat_lookup_resource (tool->seat, client);
if (seat_resource &&
!meta_wayland_tablet_tool_lookup_resource (tool, client))
{
tool_resource = meta_wayland_tablet_tool_create_new_resource (tool, client,
seat_resource,
0);
meta_wayland_tablet_seat_notify_tool (tool->seat, tool, client);
meta_wayland_tablet_tool_notify_details (tool, tool_resource);
}
}
static void
broadcast_proximity_in (MetaWaylandTabletTool *tool)
{
struct wl_resource *resource, *tablet_resource;
struct wl_client *client;
client = wl_resource_get_client (tool->focus_surface->resource);
tablet_resource = meta_wayland_tablet_lookup_resource (tool->current_tablet,
client);
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_proximity_in (resource, tool->proximity_serial,
tablet_resource,
tool->focus_surface->resource);
}
}
static void
broadcast_proximity_out (MetaWaylandTabletTool *tool)
{
struct wl_resource *resource;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_proximity_out (resource);
}
}
static void
broadcast_frame (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
guint32 _time = event ? clutter_event_get_time (event) : CLUTTER_CURRENT_TIME;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_frame (resource, _time);
}
}
static void
meta_wayland_tablet_tool_set_focus (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
if (tool->focus_surface == surface)
return;
if (tool->focus_surface != NULL)
{
struct wl_list *l;
l = &tool->focus_resource_list;
if (!wl_list_empty (l))
{
broadcast_proximity_out (tool);
broadcast_frame (tool, event);
move_resources (&tool->resource_list, &tool->focus_resource_list);
}
wl_list_remove (&tool->focus_surface_destroy_listener.link);
tool->focus_surface = NULL;
}
if (surface != NULL && tool->current_tablet)
{
struct wl_client *client;
struct wl_list *l;
tool->focus_surface = surface;
client = wl_resource_get_client (tool->focus_surface->resource);
wl_resource_add_destroy_listener (tool->focus_surface->resource,
&tool->focus_surface_destroy_listener);
move_resources_for_client (&tool->focus_resource_list,
&tool->resource_list, client);
meta_wayland_tablet_tool_ensure_resource (tool, client);
l = &tool->focus_resource_list;
if (!wl_list_empty (l))
{
struct wl_client *client = wl_resource_get_client (tool->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
tool->proximity_serial = wl_display_next_serial (display);
broadcast_proximity_in (tool);
broadcast_frame (tool, event);
}
}
meta_wayland_tablet_tool_update_cursor_surface (tool);
}
static void
tablet_tool_handle_focus_surface_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandTabletTool *tool;
tool = wl_container_of (listener, tool, focus_surface_destroy_listener);
meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
}
static void
tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandTabletTool *tool;
tool = wl_container_of (listener, tool, cursor_surface_destroy_listener);
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
}
MetaWaylandTabletTool *
meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
ClutterInputDevice *device,
ClutterInputDeviceTool *device_tool)
{
MetaWaylandTabletTool *tool;
tool = g_slice_new0 (MetaWaylandTabletTool);
tool->seat = seat;
tool->device = device;
tool->device_tool = device_tool;
wl_list_init (&tool->resource_list);
wl_list_init (&tool->focus_resource_list);
tool->focus_surface_destroy_listener.notify = tablet_tool_handle_focus_surface_destroy;
tool->cursor_surface_destroy_listener.notify = tablet_tool_handle_cursor_surface_destroy;
return tool;
}
void
meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool)
{
struct wl_resource *resource, *next;
meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
g_clear_object (&tool->cursor_renderer);
wl_resource_for_each_safe (resource, next, &tool->resource_list)
{
zwp_tablet_tool_v1_send_removed (resource);
}
g_slice_free (MetaWaylandTabletTool, tool);
}
static void
tool_set_cursor (struct wl_client *client,
struct wl_resource *resource,
uint32_t serial,
struct wl_resource *surface_resource,
int32_t hotspot_x,
int32_t hotspot_y)
{
MetaWaylandTabletTool *tool = wl_resource_get_user_data (resource);
MetaWaylandSurface *surface;
surface = (surface_resource ? wl_resource_get_user_data (surface_resource) : NULL);
if (tool->focus_surface == NULL)
return;
if (tool->cursor_renderer == NULL)
return;
if (wl_resource_get_client (tool->focus_surface->resource) != client)
return;
if (tool->proximity_serial - serial > G_MAXUINT32 / 2)
return;
if (surface &&
!meta_wayland_surface_assign_role (surface,
META_TYPE_WAYLAND_SURFACE_ROLE_CURSOR))
{
wl_resource_post_error (resource, WL_POINTER_ERROR_ROLE,
"wl_surface@%d already has a different role",
wl_resource_get_id (surface_resource));
return;
}
if (surface)
{
MetaWaylandSurfaceRoleCursor *cursor_role;
cursor_role = META_WAYLAND_SURFACE_ROLE_CURSOR (surface->role);
meta_wayland_surface_role_cursor_set_renderer (cursor_role,
tool->cursor_renderer);
meta_wayland_surface_role_cursor_set_hotspot (cursor_role,
hotspot_x, hotspot_y);
}
meta_wayland_tablet_tool_set_cursor_surface (tool, surface);
}
static void
tool_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_tool_v1_interface tool_interface = {
tool_set_cursor,
tool_destroy
};
static void
emit_proximity_in (MetaWaylandTabletTool *tool,
struct wl_resource *resource)
{
struct wl_resource *tablet_resource;
struct wl_client *client;
if (!tool->focus_surface)
return;
client = wl_resource_get_client (resource);
tablet_resource = meta_wayland_tablet_lookup_resource (tool->current_tablet,
client);
zwp_tablet_tool_v1_send_proximity_in (resource, tool->proximity_serial,
tablet_resource, tool->focus_surface->resource);
}
struct wl_resource *
meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_tool_v1_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &tool_interface,
tool, unbind_resource);
wl_resource_set_user_data (resource, tool);
if (tool->focus_surface &&
wl_resource_get_client (tool->focus_surface->resource) == client)
{
wl_list_insert (&tool->focus_resource_list, wl_resource_get_link (resource));
emit_proximity_in (tool, resource);
}
else
{
wl_list_insert (&tool->resource_list, wl_resource_get_link (resource));
}
return resource;
}
struct wl_resource *
meta_wayland_tablet_tool_lookup_resource (MetaWaylandTabletTool *tool,
struct wl_client *client)
{
struct wl_resource *resource = NULL;
if (!wl_list_empty (&tool->resource_list))
resource = wl_resource_find_for_client (&tool->resource_list, client);
if (!wl_list_empty (&tool->focus_resource_list))
resource = wl_resource_find_for_client (&tool->focus_resource_list, client);
return resource;
}
static void
meta_wayland_tablet_tool_account_button (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
if (event->type == CLUTTER_BUTTON_PRESS)
tool->pressed_buttons |= 1 << (event->button.button - 1);
else if (event->type == CLUTTER_BUTTON_RELEASE)
tool->pressed_buttons &= ~(1 << (event->button.button - 1));
}
static void
sync_focus_surface (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
MetaDisplay *display = meta_get_display ();
switch (display->event_route)
{
case META_EVENT_ROUTE_WINDOW_OP:
case META_EVENT_ROUTE_COMPOSITOR_GRAB:
case META_EVENT_ROUTE_FRAME_BUTTON:
/* The compositor has a grab, so remove our focus */
meta_wayland_tablet_tool_set_focus (tool, NULL, event);
break;
case META_EVENT_ROUTE_NORMAL:
case META_EVENT_ROUTE_WAYLAND_POPUP:
meta_wayland_tablet_tool_set_focus (tool, tool->current, event);
break;
default:
g_assert_not_reached ();
}
}
static void
repick_for_event (MetaWaylandTabletTool *tool,
const ClutterEvent *for_event)
{
ClutterActor *actor = NULL;
actor = clutter_event_get_source (for_event);
if (META_IS_SURFACE_ACTOR_WAYLAND (actor))
tool->current = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor));
else
tool->current = NULL;
sync_focus_surface (tool, for_event);
meta_wayland_tablet_tool_update_cursor_surface (tool);
}
static void
meta_wayland_tablet_tool_get_relative_coordinates (MetaWaylandTabletTool *tool,
ClutterInputDevice *device,
MetaWaylandSurface *surface,
wl_fixed_t *sx,
wl_fixed_t *sy)
{
float xf = 0.0f, yf = 0.0f;
ClutterPoint pos;
clutter_input_device_get_coords (device, NULL, &pos);
clutter_actor_transform_stage_point (CLUTTER_ACTOR (meta_surface_actor_get_texture (surface->surface_actor)),
pos.x, pos.y, &xf, &yf);
*sx = wl_fixed_from_double (xf) / surface->scale;
*sy = wl_fixed_from_double (yf) / surface->scale;
}
static void
broadcast_motion (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
ClutterInputDevice *device;
wl_fixed_t sx, sy;
device = clutter_event_get_source_device (event);
meta_wayland_tablet_tool_get_relative_coordinates (tool, device,
tool->focus_surface,
&sx, &sy);
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_motion (resource, sx, sy);
}
}
static void
broadcast_down (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
tool->down_serial = wl_display_next_serial (tool->seat->manager->wl_display);
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_down (resource, tool->down_serial);
}
}
static void
broadcast_up (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_up (resource);
}
}
static void
broadcast_button (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
guint32 button;
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,
event->type == CLUTTER_BUTTON_PRESS ?
ZWP_TABLET_TOOL_V1_BUTTON_STATE_PRESSED :
ZWP_TABLET_TOOL_V1_BUTTON_STATE_RELEASED);
}
}
static void
broadcast_axis (MetaWaylandTabletTool *tool,
const ClutterEvent *event,
ClutterInputAxis axis)
{
struct wl_resource *resource;
ClutterInputDevice *source;
uint32_t value;
gdouble val;
source = clutter_event_get_source_device (event);
if (!clutter_input_device_get_axis_value (source, event->motion.axes, axis, &val))
return;
value = val * TABLET_AXIS_MAX;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
switch (axis)
{
case CLUTTER_INPUT_AXIS_PRESSURE:
zwp_tablet_tool_v1_send_pressure (resource, value);
break;
case CLUTTER_INPUT_AXIS_DISTANCE:
zwp_tablet_tool_v1_send_distance (resource, value);
break;
case CLUTTER_INPUT_AXIS_SLIDER:
zwp_tablet_tool_v1_send_slider (resource, value);
break;
default:
break;
}
}
}
static void
broadcast_tilt (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
ClutterInputDevice *source;
gdouble xtilt, ytilt;
source = clutter_event_get_source_device (event);
if (!clutter_input_device_get_axis_value (source, event->motion.axes,
CLUTTER_INPUT_AXIS_XTILT, &xtilt) ||
!clutter_input_device_get_axis_value (source, event->motion.axes,
CLUTTER_INPUT_AXIS_YTILT, &ytilt))
return;
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));
}
}
static void
broadcast_rotation (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
struct wl_resource *resource;
ClutterInputDevice *source;
gdouble rotation;
source = clutter_event_get_source_device (event);
if (!clutter_input_device_get_axis_value (source, event->motion.axes,
CLUTTER_INPUT_AXIS_ROTATION,
&rotation))
return;
wl_resource_for_each (resource, &tool->focus_resource_list)
{
zwp_tablet_tool_v1_send_rotation (resource,
(int32_t) rotation * DEGREES_PRECISION);
}
}
static void
broadcast_axes (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
ClutterInputDevice *device;
guint32 capabilities;
if (!event->motion.axes)
return;
device = clutter_event_get_source_device (event);
capabilities = input_device_get_capabilities (device);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_PRESSURE))
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_PRESSURE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_DISTANCE))
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_DISTANCE);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_TILT))
broadcast_tilt (tool, event);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_ROTATION))
broadcast_rotation (tool, event);
if (capabilities & (1 << ZWP_TABLET_TOOL_V1_CAPABILITY_SLIDER))
broadcast_axis (tool, event, CLUTTER_INPUT_AXIS_SLIDER);
/* FIXME: Missing wp_tablet_tool.wheel */
}
static void
handle_motion_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
if (!tool->focus_surface)
return;
broadcast_motion (tool, event);
broadcast_axes (tool, event);
broadcast_frame (tool, event);
}
static void
handle_button_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
if (!tool->focus_surface)
return;
if (event->type == CLUTTER_BUTTON_PRESS && event->button.button == 1)
broadcast_down (tool, event);
else if (event->type == CLUTTER_BUTTON_RELEASE && event->button.button == 1)
broadcast_up (tool, event);
else
broadcast_button (tool, event);
broadcast_frame (tool, event);
}
void
meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
meta_wayland_tablet_tool_account_button (tool, event);
break;
case CLUTTER_MOTION:
if (!tool->pressed_buttons)
repick_for_event (tool, event);
break;
case CLUTTER_PROXIMITY_IN:
if (!tool->cursor_renderer)
tool->cursor_renderer = meta_cursor_renderer_new ();
tool->current_tablet =
meta_wayland_tablet_seat_lookup_tablet (tool->seat,
clutter_event_get_source_device (event));
break;
case CLUTTER_PROXIMITY_OUT:
tool->current_tablet = NULL;
meta_wayland_tablet_tool_update_cursor_surface (tool);
g_clear_object (&tool->cursor_renderer);
break;
default:
break;
}
}
gboolean
meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
switch (event->type)
{
case CLUTTER_PROXIMITY_IN:
/* We don't have much info here to make anything useful out of it,
* wait until the first motion event so we have both coordinates
* and tool.
*/
break;
case CLUTTER_PROXIMITY_OUT:
meta_wayland_tablet_tool_set_focus (tool, NULL, event);
break;
case CLUTTER_MOTION:
handle_motion_event (tool, event);
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
handle_button_event (tool, event);
break;
default:
return CLUTTER_EVENT_PROPAGATE;
}
return CLUTTER_EVENT_STOP;
}
void
meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool *tool,
int new_x,
int new_y)
{
if (tool->cursor_renderer)
meta_cursor_renderer_set_position (tool->cursor_renderer, new_x, new_y);
}

View File

@ -0,0 +1,81 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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_TOOL_H
#define META_WAYLAND_TABLET_TOOL_H
#include <wayland-server.h>
#include <glib.h>
#include "meta-wayland-types.h"
#include "meta-cursor-renderer.h"
struct _MetaWaylandTabletTool
{
MetaWaylandTabletSeat *seat;
ClutterInputDevice *device;
ClutterInputDeviceTool *device_tool;
struct wl_list resource_list;
struct wl_list focus_resource_list;
MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_destroy_listener;
MetaWaylandSurface *cursor_surface;
struct wl_listener cursor_surface_destroy_listener;
MetaCursorRenderer *cursor_renderer;
MetaWaylandSurface *current;
guint32 pressed_buttons;
guint32 proximity_serial;
guint32 down_serial;
guint32 button_serial;
MetaWaylandTablet *current_tablet;
};
MetaWaylandTabletTool * meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
ClutterInputDevice *device,
ClutterInputDeviceTool *device_tool);
void meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool);
struct wl_resource *
meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id);
struct wl_resource *
meta_wayland_tablet_tool_lookup_resource (MetaWaylandTabletTool *tool,
struct wl_client *client);
void meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
const ClutterEvent *event);
gboolean meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event);
void meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool *tool,
int new_x,
int new_y);
#endif /* META_WAYLAND_TABLET_TOOL_H */

View File

@ -0,0 +1,130 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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-v1-server-protocol.h"
#include "meta-surface-actor-wayland.h"
#include "meta-wayland-private.h"
#include "meta-wayland-tablet.h"
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
MetaWaylandTablet *
meta_wayland_tablet_new (ClutterInputDevice *device,
MetaWaylandTabletSeat *tablet_seat)
{
MetaWaylandTablet *tablet;
tablet = g_slice_new0 (MetaWaylandTablet);
wl_list_init (&tablet->resource_list);
wl_list_init (&tablet->focus_resource_list);
tablet->device = device;
tablet->tablet_seat = tablet_seat;
return tablet;
}
void
meta_wayland_tablet_free (MetaWaylandTablet *tablet)
{
struct wl_resource *resource, *next;
wl_resource_for_each_safe (resource, next, &tablet->resource_list)
{
zwp_tablet_v1_send_removed (resource);
}
g_slice_free (MetaWaylandTablet, tablet);
}
static void
tablet_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_tablet_v1_interface tablet_interface = {
tablet_destroy
};
void
meta_wayland_tablet_notify (MetaWaylandTablet *tablet,
struct wl_resource *resource)
{
ClutterInputDevice *device = tablet->device;
guint vid, pid;
zwp_tablet_v1_send_name (resource, clutter_input_device_get_device_name (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);
/* FIXME: zwp_tablet_v1.path missing */
zwp_tablet_v1_send_done (resource);
}
struct wl_resource *
meta_wayland_tablet_create_new_resource (MetaWaylandTablet *tablet,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_tablet_v1_interface,
wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (resource, &tablet_interface,
tablet, unbind_resource);
wl_resource_set_user_data (resource, tablet);
wl_list_insert (&tablet->resource_list, wl_resource_get_link (resource));
return resource;
}
struct wl_resource *
meta_wayland_tablet_lookup_resource (MetaWaylandTablet *tablet,
struct wl_client *client)
{
struct wl_resource *resource;
resource = wl_resource_find_for_client (&tablet->resource_list, client);
if (!resource)
resource = wl_resource_find_for_client (&tablet->focus_resource_list, client);
return resource;
}

View File

@ -0,0 +1,59 @@
/*
* Wayland Support
*
* Copyright (C) 2015 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_H
#define META_WAYLAND_TABLET_H
#include <wayland-server.h>
#include <glib.h>
#include "meta-wayland-types.h"
#include "meta-cursor-renderer.h"
struct _MetaWaylandTablet
{
MetaWaylandTabletSeat *tablet_seat;
ClutterInputDevice *device;
struct wl_list resource_list;
struct wl_list focus_resource_list;
MetaWaylandSurface *current;
};
MetaWaylandTablet * meta_wayland_tablet_new (ClutterInputDevice *device,
MetaWaylandTabletSeat *tablet_seat);
void meta_wayland_tablet_free (MetaWaylandTablet *tablet);
struct wl_resource *
meta_wayland_tablet_create_new_resource (MetaWaylandTablet *tablet,
struct wl_client *client,
struct wl_resource *seat_resource,
uint32_t id);
struct wl_resource *
meta_wayland_tablet_lookup_resource (MetaWaylandTablet *tablet,
struct wl_client *client);
void meta_wayland_tablet_notify (MetaWaylandTablet *tablet,
struct wl_resource *resource);
#endif /* META_WAYLAND_TABLET_H */

View File

@ -36,6 +36,11 @@ typedef struct _MetaWaylandDragDestFuncs MetaWaylandDragDestFuncs;
typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
typedef struct _MetaWaylandDataDevice MetaWaylandDataDevice;
typedef struct _MetaWaylandTabletManager MetaWaylandTabletManager;
typedef struct _MetaWaylandTabletSeat MetaWaylandTabletSeat;
typedef struct _MetaWaylandTabletTool MetaWaylandTabletTool;
typedef struct _MetaWaylandTablet MetaWaylandTablet;
typedef struct _MetaWaylandBuffer MetaWaylandBuffer;
typedef struct _MetaWaylandRegion MetaWaylandRegion;

View File

@ -39,6 +39,7 @@
#include "meta-wayland-seat.h"
#include "meta-wayland-outputs.h"
#include "meta-wayland-data-device.h"
#include "meta-wayland-tablet-manager.h"
static MetaWaylandCompositor _meta_wayland_compositor;
@ -167,7 +168,10 @@ void
meta_wayland_compositor_update (MetaWaylandCompositor *compositor,
const ClutterEvent *event)
{
meta_wayland_seat_update (compositor->seat, event);
if (meta_wayland_tablet_manager_consumes_event (compositor->tablet_manager, event))
meta_wayland_tablet_manager_update (compositor->tablet_manager, event);
else
meta_wayland_seat_update (compositor->seat, event);
}
void
@ -196,6 +200,10 @@ gboolean
meta_wayland_compositor_handle_event (MetaWaylandCompositor *compositor,
const ClutterEvent *event)
{
if (meta_wayland_tablet_manager_handle_event (compositor->tablet_manager,
event))
return TRUE;
return meta_wayland_seat_handle_event (compositor->seat, event);
}
@ -327,6 +335,7 @@ meta_wayland_init (void)
meta_wayland_data_device_manager_init (compositor);
meta_wayland_shell_init (compositor);
meta_wayland_pointer_gestures_init (compositor);
meta_wayland_tablet_manager_init (compositor);
meta_wayland_seat_init (compositor);
meta_wayland_relative_pointer_init (compositor);
meta_wayland_pointer_constraints_init (compositor);