Compare commits
	
		
			31 Commits
		
	
	
		
			3.37.1
			...
			wip/tablet
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 25bbb4cc40 | ||
|   | 3a963d95db | ||
|   | 212a170ae2 | ||
|   | 17f2b4ea43 | ||
|   | 4ce4f4eac9 | ||
|   | d7b8db3c96 | ||
|   | 754a4bf287 | ||
|   | d46586e383 | ||
|   | 38bff73d30 | ||
|   | aaa59ab6a7 | ||
|   | dff045963a | ||
|   | 6bbd6d2948 | ||
|   | 2ea01aa428 | ||
|   | 1a31721e57 | ||
|   | 033c78a7a2 | ||
|   | f1afc604d9 | ||
|   | c89edb29f9 | ||
|   | c28fc68df1 | ||
|   | 5774875ab9 | ||
|   | 422284e0cd | ||
|   | c72ad23b84 | ||
|   | d0d343352c | ||
|   | feff353081 | ||
|   | 216298dfad | ||
|   | efd90eb471 | ||
|   | 63b1a55283 | ||
|   | aa0eea9814 | ||
|   | fe5f12ddb5 | ||
|   | 8110197df4 | ||
|   | 8d290f182a | ||
|   | 9d06421c1f | 
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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__ */ | ||||
|   | ||||
| @@ -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__ */ | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
							
								
								
									
										172
									
								
								clutter/clutter/clutter-input-device-tool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								clutter/clutter/clutter-input-device-tool.c
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
							
								
								
									
										66
									
								
								clutter/clutter/clutter-input-device-tool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								clutter/clutter/clutter-input-device-tool.h
									
									
									
									
									
										Normal 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__ */ | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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)) | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
							
								
								
									
										71
									
								
								clutter/clutter/evdev/clutter-input-device-tool-evdev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								clutter/clutter/evdev/clutter-input-device-tool-evdev.c
									
									
									
									
									
										Normal 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); | ||||
| } | ||||
							
								
								
									
										77
									
								
								clutter/clutter/evdev/clutter-input-device-tool-evdev.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								clutter/clutter/evdev/clutter-input-device-tool-evdev.h
									
									
									
									
									
										Normal 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__ */ | ||||
| @@ -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		\ | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -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 */ | ||||
|   | ||||
| @@ -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 */ | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										281
									
								
								src/wayland/meta-wayland-surface-role-cursor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								src/wayland/meta-wayland-surface-role-cursor.c
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
							
								
								
									
										47
									
								
								src/wayland/meta-wayland-surface-role-cursor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/wayland/meta-wayland-surface-role-cursor.h
									
									
									
									
									
										Normal 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 */ | ||||
| @@ -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 | ||||
|   | ||||
| @@ -198,6 +198,7 @@ struct _MetaWaylandSurface | ||||
|   MetaWaylandSerial acked_configure_serial; | ||||
|   gboolean has_set_geometry; | ||||
|   gboolean is_modal; | ||||
|   gboolean destroying; | ||||
|  | ||||
|   /* xdg_popup */ | ||||
|   struct { | ||||
|   | ||||
							
								
								
									
										267
									
								
								src/wayland/meta-wayland-tablet-manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								src/wayland/meta-wayland-tablet-manager.c
									
									
									
									
									
										Normal 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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										57
									
								
								src/wayland/meta-wayland-tablet-manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/wayland/meta-wayland-tablet-manager.h
									
									
									
									
									
										Normal 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 */ | ||||
							
								
								
									
										334
									
								
								src/wayland/meta-wayland-tablet-seat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								src/wayland/meta-wayland-tablet-seat.c
									
									
									
									
									
										Normal 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); | ||||
| } | ||||
							
								
								
									
										66
									
								
								src/wayland/meta-wayland-tablet-seat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/wayland/meta-wayland-tablet-seat.h
									
									
									
									
									
										Normal 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 */ | ||||
							
								
								
									
										890
									
								
								src/wayland/meta-wayland-tablet-tool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										890
									
								
								src/wayland/meta-wayland-tablet-tool.c
									
									
									
									
									
										Normal 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); | ||||
| } | ||||
							
								
								
									
										81
									
								
								src/wayland/meta-wayland-tablet-tool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/wayland/meta-wayland-tablet-tool.h
									
									
									
									
									
										Normal 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 */ | ||||
							
								
								
									
										130
									
								
								src/wayland/meta-wayland-tablet.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/wayland/meta-wayland-tablet.c
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
							
								
								
									
										59
									
								
								src/wayland/meta-wayland-tablet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/wayland/meta-wayland-tablet.h
									
									
									
									
									
										Normal 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 */ | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user