/* GestureController.c generated by valac 0.56.18-dirty, the Vala compiler
 * generated from GestureController.vala, do not modify */

/*
 * Copyright 2025 elementary, Inc. (https://elementary.io)
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * Authored by: Leonhard Kargl <leo.kargl@proton.me>
 */

#include "gala.h"
#include <glib.h>
#include <float.h>
#include <math.h>
#include <gee.h>
#include <glib-object.h>
#include <clutter/clutter.h>
#include <meta/prefs.h>

#define GALA_GESTURE_CONTROLLER_SUCCESS_VELOCITY_THRESHOLD 0.003
#define GALA_GESTURE_CONTROLLER_MAX_VELOCITY 0.01
#if !defined(VALA_STRICT_C)
#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ >= 14)
#pragma GCC diagnostic warning "-Wincompatible-pointer-types"
#elif defined(__clang__) && (__clang_major__ >= 16)
#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types"
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
#endif
#endif

#define GALA_TYPE_GESTURE_BACKEND (gala_gesture_backend_get_type ())
#define GALA_GESTURE_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GALA_TYPE_GESTURE_BACKEND, GalaGestureBackend))
#define GALA_IS_GESTURE_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GALA_TYPE_GESTURE_BACKEND))
#define GALA_GESTURE_BACKEND_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GALA_TYPE_GESTURE_BACKEND, GalaGestureBackendIface))

typedef struct _GalaGestureBackend GalaGestureBackend;
typedef struct _GalaGestureBackendIface GalaGestureBackendIface;
enum  {
	GALA_GESTURE_CONTROLLER_0_PROPERTY,
	GALA_GESTURE_CONTROLLER_ACTION_PROPERTY,
	GALA_GESTURE_CONTROLLER_TARGET_PROPERTY,
	GALA_GESTURE_CONTROLLER_DISTANCE_PROPERTY,
	GALA_GESTURE_CONTROLLER_OVERSHOOT_LOWER_CLAMP_PROPERTY,
	GALA_GESTURE_CONTROLLER_OVERSHOOT_UPPER_CLAMP_PROPERTY,
	GALA_GESTURE_CONTROLLER_FOLLOW_NATURAL_SCROLL_PROPERTY,
	GALA_GESTURE_CONTROLLER_SNAP_PROPERTY,
	GALA_GESTURE_CONTROLLER_PROGRESS_PROPERTY,
	GALA_GESTURE_CONTROLLER_ENABLED_PROPERTY,
	GALA_GESTURE_CONTROLLER_RECOGNIZING_PROPERTY,
	GALA_GESTURE_CONTROLLER_NUM_PROPERTIES
};
static GParamSpec* gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_NUM_PROPERTIES];
#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))

#define GALA_TYPE_GESTURE (gala_gesture_get_type ())
#define GALA_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GALA_TYPE_GESTURE, GalaGesture))
#define GALA_GESTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GALA_TYPE_GESTURE, GalaGestureClass))
#define GALA_IS_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GALA_TYPE_GESTURE))
#define GALA_IS_GESTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GALA_TYPE_GESTURE))
#define GALA_GESTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GALA_TYPE_GESTURE, GalaGestureClass))

typedef struct _GalaGesture GalaGesture;
typedef struct _GalaGestureClass GalaGestureClass;
typedef struct _GalaGesturePrivate GalaGesturePrivate;
typedef enum  {
	GALA_GESTURE_DIRECTION_UNKNOWN = 0,
	GALA_GESTURE_DIRECTION_UP = 1,
	GALA_GESTURE_DIRECTION_DOWN = 2,
	GALA_GESTURE_DIRECTION_LEFT = 3,
	GALA_GESTURE_DIRECTION_RIGHT = 4,
	GALA_GESTURE_DIRECTION_IN = 5,
	GALA_GESTURE_DIRECTION_OUT = 6
} GalaGestureDirection;

#define GALA_TYPE_GESTURE_DIRECTION (gala_gesture_direction_get_type ())
#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; }
#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; }
#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);

struct _GalaGestureBackendIface {
	GTypeInterface parent_iface;
	void (*cancel_gesture) (GalaGestureBackend* self);
};

struct _GalaGestureControllerPrivate {
	GalaGestureAction _action;
	GalaRootTarget* _target;
	gdouble _distance;
	gdouble _overshoot_lower_clamp;
	gdouble _overshoot_upper_clamp;
	gboolean _follow_natural_scroll;
	gboolean _snap;
	gdouble _progress;
	gboolean _enabled;
	gboolean _recognizing;
	GeeList* backends;
	GeeList* triggers;
	GalaGestureBackend* recognizing_backend;
	gdouble gesture_progress;
	gdouble previous_percentage;
	guint64 previous_time;
	gdouble previous_delta;
	gdouble velocity;
	gint direction_multiplier;
	GalaSpringTimeline* timeline;
};

struct _GalaGesture {
	GTypeInstance parent_instance;
	volatile int ref_count;
	GalaGesturePrivate * priv;
	ClutterEventType type;
	GalaGestureDirection direction;
	gint fingers;
	ClutterInputDeviceType performed_on_device_type;
};

struct _GalaGestureClass {
	GTypeClass parent_class;
	void (*finalize) (GalaGesture *self);
};

static gint GalaGestureController_private_offset;
static gpointer gala_gesture_controller_parent_class = NULL;

 G_GNUC_INTERNAL GType gala_gesture_backend_get_type (void) G_GNUC_CONST  G_GNUC_UNUSED ;
static void gala_gesture_controller_set_target (GalaGestureController* self,
                                         GalaRootTarget* value);
 G_GNUC_INTERNAL void gala_gesture_trigger_enable_backends (GalaGestureTrigger* self,
                                           GalaGestureController* controller);
 G_GNUC_INTERNAL void gala_gesture_controller_enable_backend (GalaGestureController* self,
                                             GalaGestureBackend* backend);
 G_GNUC_INTERNAL gpointer gala_gesture_ref (gpointer instance);
 G_GNUC_INTERNAL void gala_gesture_unref (gpointer instance);
 G_GNUC_INTERNAL GParamSpec* gala_param_spec_gesture (const gchar* name,
                                     const gchar* nick,
                                     const gchar* blurb,
                                     GType object_type,
                                     GParamFlags flags);
 G_GNUC_INTERNAL void gala_value_set_gesture (GValue* value,
                             gpointer v_object) G_GNUC_UNUSED ;
 G_GNUC_INTERNAL void gala_value_take_gesture (GValue* value,
                              gpointer v_object);
 G_GNUC_INTERNAL gpointer gala_value_get_gesture (const GValue* value) G_GNUC_UNUSED ;
 G_GNUC_INTERNAL GType gala_gesture_get_type (void) G_GNUC_CONST  G_GNUC_UNUSED ;
static gboolean gala_gesture_controller_gesture_detected (GalaGestureController* self,
                                                   GalaGestureBackend* backend,
                                                   GalaGesture* gesture,
                                                   guint32 timestamp);
static gboolean _gala_gesture_controller_gesture_detected_gala_gesture_backend_on_gesture_detected (GalaGestureBackend* _sender,
                                                                                             GalaGesture* gesture,
                                                                                             guint32 timestamp,
                                                                                             gpointer self);
static void gala_gesture_controller_gesture_begin (GalaGestureController* self,
                                            gdouble percentage,
                                            guint64 elapsed_time);
static void _gala_gesture_controller_gesture_begin_gala_gesture_backend_on_begin (GalaGestureBackend* _sender,
                                                                           gdouble percentage,
                                                                           guint64 time,
                                                                           gpointer self);
static void gala_gesture_controller_gesture_update (GalaGestureController* self,
                                             gdouble percentage,
                                             guint64 elapsed_time);
static void _gala_gesture_controller_gesture_update_gala_gesture_backend_on_update (GalaGestureBackend* _sender,
                                                                             gdouble percentage,
                                                                             guint64 time,
                                                                             gpointer self);
static void gala_gesture_controller_gesture_end (GalaGestureController* self,
                                          gdouble percentage,
                                          guint64 elapsed_time);
static void _gala_gesture_controller_gesture_end_gala_gesture_backend_on_end (GalaGestureBackend* _sender,
                                                                       gdouble percentage,
                                                                       guint64 time,
                                                                       gpointer self);
static void gala_gesture_controller_prepare (GalaGestureController* self);
 G_GNUC_INTERNAL gboolean gala_gesture_trigger_triggers (GalaGestureTrigger* self,
                                        GalaGesture* gesture);
static void gala_gesture_controller_set_recognizing (GalaGestureController* self,
                                              gboolean value);
 G_GNUC_INTERNAL GType gala_gesture_direction_get_type (void) G_GNUC_CONST ;
 G_GNUC_INTERNAL gboolean gala_gesture_settings_is_natural_scroll_enabled (ClutterInputDeviceType device_type);
static void gala_gesture_controller_update_gesture_progress (GalaGestureController* self,
                                                      gdouble percentage,
                                                      gdouble percentage_delta);
static void gala_gesture_controller_finish (GalaGestureController* self,
                                     gdouble velocity,
                                     gdouble to);
static void gala_gesture_controller_finished (GalaGestureController* self,
                                       gboolean is_finished);
static void __lambda22_ (GalaGestureController* self,
                  gdouble value);
static void ___lambda22__gala_spring_timeline_progress (GalaSpringTimeline* _sender,
                                                 gdouble value,
                                                 gpointer self);
static void _gala_gesture_controller_finished_clutter_timeline_stopped (ClutterTimeline* _sender,
                                                                 gboolean is_finished,
                                                                 gpointer self);
 G_GNUC_INTERNAL void gala_gesture_backend_cancel_gesture (GalaGestureBackend* self);
static GObject * gala_gesture_controller_constructor (GType type,
                                               guint n_construct_properties,
                                               GObjectConstructParam * construct_properties);
static void gala_gesture_controller_finalize (GObject * obj);
static GType gala_gesture_controller_get_type_once (void);
static void _vala_gala_gesture_controller_get_property (GObject * object,
                                                 guint property_id,
                                                 GValue * value,
                                                 GParamSpec * pspec);
static void _vala_gala_gesture_controller_set_property (GObject * object,
                                                 guint property_id,
                                                 const GValue * value,
                                                 GParamSpec * pspec);

static inline gpointer
gala_gesture_controller_get_instance_private (GalaGestureController* self)
{
	return G_STRUCT_MEMBER_P (self, GalaGestureController_private_offset);
}

GalaGestureController*
gala_gesture_controller_construct (GType object_type,
                                   GalaGestureAction action)
{
	GalaGestureController * self = NULL;
	self = (GalaGestureController*) g_object_new (object_type, "action", action, NULL);
	return self;
}

GalaGestureController*
gala_gesture_controller_new (GalaGestureAction action)
{
	return gala_gesture_controller_construct (GALA_TYPE_GESTURE_CONTROLLER, action);
}

/**
     * Do not call this directly, use {@link RooTarget.add_controller} instead.
     */
void
gala_gesture_controller_attached (GalaGestureController* self,
                                  GalaRootTarget* target)
{
	g_return_if_fail (self != NULL);
	g_return_if_fail (target != NULL);
	g_object_ref ((GObject*) self);
	gala_gesture_controller_set_target (self, target);
}

void
gala_gesture_controller_detached (GalaGestureController* self)
{
	g_return_if_fail (self != NULL);
	self->priv->_target = NULL;
	g_object_unref ((GObject*) self);
}

void
gala_gesture_controller_add_trigger (GalaGestureController* self,
                                     GalaGestureTrigger* trigger)
{
	GeeList* _tmp0_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (trigger != NULL);
	_tmp0_ = self->priv->triggers;
	gee_collection_add ((GeeCollection*) _tmp0_, trigger);
	gala_gesture_trigger_enable_backends (trigger, self);
}

static gboolean
_gala_gesture_controller_gesture_detected_gala_gesture_backend_on_gesture_detected (GalaGestureBackend* _sender,
                                                                                    GalaGesture* gesture,
                                                                                    guint32 timestamp,
                                                                                    gpointer self)
{
	gboolean result;
	result = gala_gesture_controller_gesture_detected ((GalaGestureController*) self, _sender, gesture, timestamp);
	return result;
}

static void
_gala_gesture_controller_gesture_begin_gala_gesture_backend_on_begin (GalaGestureBackend* _sender,
                                                                      gdouble percentage,
                                                                      guint64 time,
                                                                      gpointer self)
{
	gala_gesture_controller_gesture_begin ((GalaGestureController*) self, percentage, time);
}

static void
_gala_gesture_controller_gesture_update_gala_gesture_backend_on_update (GalaGestureBackend* _sender,
                                                                        gdouble percentage,
                                                                        guint64 time,
                                                                        gpointer self)
{
	gala_gesture_controller_gesture_update ((GalaGestureController*) self, percentage, time);
}

static void
_gala_gesture_controller_gesture_end_gala_gesture_backend_on_end (GalaGestureBackend* _sender,
                                                                  gdouble percentage,
                                                                  guint64 time,
                                                                  gpointer self)
{
	gala_gesture_controller_gesture_end ((GalaGestureController*) self, percentage, time);
}

 G_GNUC_INTERNAL void
gala_gesture_controller_enable_backend (GalaGestureController* self,
                                        GalaGestureBackend* backend)
{
	GeeList* _tmp0_;
	g_return_if_fail (self != NULL);
	g_return_if_fail (backend != NULL);
	g_signal_connect_object (backend, "on-gesture-detected", (GCallback) _gala_gesture_controller_gesture_detected_gala_gesture_backend_on_gesture_detected, self, 0);
	g_signal_connect_object (backend, "on-begin", (GCallback) _gala_gesture_controller_gesture_begin_gala_gesture_backend_on_begin, self, 0);
	g_signal_connect_object (backend, "on-update", (GCallback) _gala_gesture_controller_gesture_update_gala_gesture_backend_on_update, self, 0);
	g_signal_connect_object (backend, "on-end", (GCallback) _gala_gesture_controller_gesture_end_gala_gesture_backend_on_end, self, 0);
	_tmp0_ = self->priv->backends;
	gee_collection_add ((GeeCollection*) _tmp0_, backend);
}

static void
gala_gesture_controller_prepare (GalaGestureController* self)
{
	GalaSpringTimeline* _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->timeline;
	if (_tmp0_ != NULL) {
		_g_object_unref0 (self->priv->timeline);
		self->priv->timeline = NULL;
	} else {
		GalaRootTarget* _tmp1_;
		GalaRootTarget* _tmp2_;
		GalaGestureAction _tmp3_;
		gdouble _tmp4_;
		gdouble _tmp5_;
		_tmp1_ = gala_gesture_controller_get_target (self);
		_tmp2_ = _tmp1_;
		_tmp3_ = self->priv->_action;
		_tmp4_ = gala_gesture_controller_get_progress (self);
		_tmp5_ = _tmp4_;
		gala_gesture_target_propagate ((GalaGestureTarget*) _tmp2_, GALA_GESTURE_TARGET_UPDATE_TYPE_START, _tmp3_, _tmp5_);
	}
}

static gpointer
_g_object_ref0 (gpointer self)
{
	return self ? g_object_ref (self) : NULL;
}

static gboolean
gala_gesture_controller_gesture_detected (GalaGestureController* self,
                                          GalaGestureBackend* backend,
                                          GalaGesture* gesture,
                                          guint32 timestamp)
{
	gboolean _tmp0_ = FALSE;
	gboolean _tmp1_;
	gboolean _tmp13_;
	gboolean _tmp19_;
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	g_return_val_if_fail (backend != NULL, FALSE);
	g_return_val_if_fail (gesture != NULL, FALSE);
	_tmp1_ = self->priv->_recognizing;
	if (_tmp1_) {
		_tmp0_ = TRUE;
	} else {
		gboolean _tmp2_;
		gboolean _tmp3_;
		_tmp2_ = gala_gesture_controller_get_enabled (self);
		_tmp3_ = _tmp2_;
		_tmp0_ = !_tmp3_;
	}
	if (_tmp0_) {
		result = FALSE;
		return result;
	}
	{
		GeeList* _trigger_list = NULL;
		GeeList* _tmp4_;
		gint _trigger_size = 0;
		GeeList* _tmp5_;
		gint _tmp6_;
		gint _tmp7_;
		gint _trigger_index = 0;
		_tmp4_ = self->priv->triggers;
		_trigger_list = _tmp4_;
		_tmp5_ = _trigger_list;
		_tmp6_ = gee_collection_get_size ((GeeCollection*) _tmp5_);
		_tmp7_ = _tmp6_;
		_trigger_size = _tmp7_;
		_trigger_index = -1;
		while (TRUE) {
			gint _tmp8_;
			gint _tmp9_;
			GalaGestureTrigger* trigger = NULL;
			GeeList* _tmp10_;
			gpointer _tmp11_;
			GalaGestureTrigger* _tmp12_;
			_trigger_index = _trigger_index + 1;
			_tmp8_ = _trigger_index;
			_tmp9_ = _trigger_size;
			if (!(_tmp8_ < _tmp9_)) {
				break;
			}
			_tmp10_ = _trigger_list;
			_tmp11_ = gee_list_get (_tmp10_, _trigger_index);
			trigger = (GalaGestureTrigger*) _tmp11_;
			_tmp12_ = trigger;
			if (gala_gesture_trigger_triggers (_tmp12_, gesture)) {
				gala_gesture_controller_set_recognizing (self, TRUE);
				_g_object_unref0 (trigger);
				break;
			}
			_g_object_unref0 (trigger);
		}
	}
	_tmp13_ = self->priv->_recognizing;
	if (_tmp13_) {
		gboolean _tmp14_ = FALSE;
		gboolean _tmp15_ = FALSE;
		gboolean _tmp16_ = FALSE;
		gboolean _tmp17_;
		GalaGestureBackend* _tmp18_;
		if (gesture->direction == GALA_GESTURE_DIRECTION_UP) {
			_tmp15_ = TRUE;
		} else {
			_tmp15_ = gesture->direction == GALA_GESTURE_DIRECTION_RIGHT;
		}
		if (_tmp15_) {
			_tmp14_ = TRUE;
		} else {
			_tmp14_ = gesture->direction == GALA_GESTURE_DIRECTION_OUT;
		}
		if (_tmp14_) {
			self->priv->direction_multiplier = 1;
		} else {
			self->priv->direction_multiplier = -1;
		}
		_tmp17_ = self->priv->_follow_natural_scroll;
		if (_tmp17_) {
			_tmp16_ = !gala_gesture_settings_is_natural_scroll_enabled (gesture->performed_on_device_type);
		} else {
			_tmp16_ = FALSE;
		}
		if (_tmp16_) {
			self->priv->direction_multiplier = self->priv->direction_multiplier * -1;
		}
		_tmp18_ = _g_object_ref0 (backend);
		_g_object_unref0 (self->priv->recognizing_backend);
		self->priv->recognizing_backend = _tmp18_;
	}
	_tmp19_ = self->priv->_recognizing;
	result = _tmp19_;
	return result;
}

static void
gala_gesture_controller_gesture_begin (GalaGestureController* self,
                                       gdouble percentage,
                                       guint64 elapsed_time)
{
	gboolean _tmp0_;
	gdouble _tmp1_;
	gdouble _tmp2_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_recognizing;
	if (!_tmp0_) {
		return;
	}
	gala_gesture_controller_prepare (self);
	_tmp1_ = gala_gesture_controller_get_progress (self);
	_tmp2_ = _tmp1_;
	self->priv->gesture_progress = _tmp2_;
	self->priv->previous_percentage = percentage;
	self->priv->previous_time = elapsed_time;
}

static void
gala_gesture_controller_gesture_update (GalaGestureController* self,
                                        gdouble percentage,
                                        guint64 elapsed_time)
{
	gboolean _tmp0_;
	gdouble updated_delta = 0.0;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_recognizing;
	if (!_tmp0_) {
		return;
	}
	updated_delta = self->priv->previous_delta;
	if (elapsed_time != self->priv->previous_time) {
		gdouble distance = 0.0;
		gdouble time = 0.0;
		distance = percentage - self->priv->previous_percentage;
		time = (gdouble) (elapsed_time - self->priv->previous_time);
		self->priv->velocity = distance / time;
		if (self->priv->velocity > GALA_GESTURE_CONTROLLER_MAX_VELOCITY) {
			gdouble used_percentage = 0.0;
			self->priv->velocity = GALA_GESTURE_CONTROLLER_MAX_VELOCITY;
			used_percentage = (GALA_GESTURE_CONTROLLER_MAX_VELOCITY * time) + self->priv->previous_percentage;
			updated_delta += percentage - used_percentage;
		}
	}
	gala_gesture_controller_update_gesture_progress (self, percentage, updated_delta);
	self->priv->previous_percentage = percentage;
	self->priv->previous_time = elapsed_time;
	self->priv->previous_delta = updated_delta;
}

static void
gala_gesture_controller_gesture_end (GalaGestureController* self,
                                     gdouble percentage,
                                     guint64 elapsed_time)
{
	gboolean _tmp0_;
	gdouble to = 0.0;
	gdouble _tmp1_;
	gdouble _tmp2_;
	gboolean _tmp3_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_recognizing;
	if (!_tmp0_) {
		return;
	}
	gala_gesture_controller_set_recognizing (self, FALSE);
	gala_gesture_controller_update_gesture_progress (self, percentage, self->priv->previous_delta);
	_tmp1_ = gala_gesture_controller_get_progress (self);
	_tmp2_ = _tmp1_;
	to = _tmp2_;
	_tmp3_ = self->priv->_snap;
	if (_tmp3_) {
		if (fabs (self->priv->velocity) > GALA_GESTURE_CONTROLLER_SUCCESS_VELOCITY_THRESHOLD) {
			gint _tmp4_ = 0;
			if (self->priv->velocity > ((gdouble) 0)) {
				_tmp4_ = self->priv->direction_multiplier;
			} else {
				_tmp4_ = -self->priv->direction_multiplier;
			}
			to += _tmp4_ * 0.5;
		}
		to = round (to);
	}
	gala_gesture_controller_finish (self, self->priv->velocity * self->priv->direction_multiplier, to);
	self->priv->gesture_progress = (gdouble) 0;
	self->priv->previous_percentage = (gdouble) 0;
	self->priv->previous_time = (guint64) 0;
	self->priv->previous_delta = (gdouble) 0;
	self->priv->velocity = (gdouble) 0;
	self->priv->direction_multiplier = 0;
}

static void
gala_gesture_controller_update_gesture_progress (GalaGestureController* self,
                                                 gdouble percentage,
                                                 gdouble percentage_delta)
{
	gint lower_clamp_int = 0;
	gdouble _tmp0_;
	gint upper_clamp_int = 0;
	gdouble _tmp1_;
	gdouble stretched_percentage = 0.0;
	gdouble clamped = 0.0;
	g_return_if_fail (self != NULL);
	self->priv->gesture_progress = self->priv->gesture_progress + (((percentage - percentage_delta) - (self->priv->previous_percentage - self->priv->previous_delta)) * self->priv->direction_multiplier);
	_tmp0_ = self->priv->_overshoot_lower_clamp;
	lower_clamp_int = (gint) _tmp0_;
	_tmp1_ = self->priv->_overshoot_upper_clamp;
	upper_clamp_int = (gint) _tmp1_;
	stretched_percentage = (gdouble) 0;
	if (self->priv->gesture_progress < ((gdouble) lower_clamp_int)) {
		gdouble _tmp2_;
		_tmp2_ = self->priv->_overshoot_lower_clamp;
		stretched_percentage = (self->priv->gesture_progress - lower_clamp_int) * (-(_tmp2_ - lower_clamp_int));
	} else {
		if (self->priv->gesture_progress > ((gdouble) upper_clamp_int)) {
			gdouble _tmp3_;
			_tmp3_ = self->priv->_overshoot_upper_clamp;
			stretched_percentage = (self->priv->gesture_progress - upper_clamp_int) * (_tmp3_ - upper_clamp_int);
		}
	}
	clamped = CLAMP (self->priv->gesture_progress, (gdouble) lower_clamp_int, (gdouble) upper_clamp_int);
	gala_gesture_controller_set_progress (self, clamped + stretched_percentage);
}

static void
__lambda22_ (GalaGestureController* self,
             gdouble value)
{
	gala_gesture_controller_set_progress (self, value);
}

static void
___lambda22__gala_spring_timeline_progress (GalaSpringTimeline* _sender,
                                            gdouble value,
                                            gpointer self)
{
	__lambda22_ ((GalaGestureController*) self, value);
}

static void
_gala_gesture_controller_finished_clutter_timeline_stopped (ClutterTimeline* _sender,
                                                            gboolean is_finished,
                                                            gpointer self)
{
	gala_gesture_controller_finished ((GalaGestureController*) self, is_finished);
}

static void
gala_gesture_controller_finish (GalaGestureController* self,
                                gdouble velocity,
                                gdouble to)
{
	gdouble clamped_to = 0.0;
	gdouble _tmp0_;
	gdouble _tmp1_;
	GalaRootTarget* _tmp2_;
	GalaRootTarget* _tmp3_;
	GalaGestureAction _tmp4_;
	gdouble _tmp5_;
	gdouble _tmp6_;
	GalaSpringTimeline* spring = NULL;
	GalaRootTarget* _tmp7_;
	GalaRootTarget* _tmp8_;
	ClutterActor* _tmp9_;
	ClutterActor* _tmp10_;
	gdouble _tmp11_;
	gdouble _tmp12_;
	GalaSpringTimeline* _tmp13_;
	GalaSpringTimeline* _tmp14_;
	GalaSpringTimeline* _tmp15_;
	GalaSpringTimeline* _tmp16_;
	GalaSpringTimeline* _tmp17_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_overshoot_lower_clamp;
	_tmp1_ = self->priv->_overshoot_upper_clamp;
	clamped_to = CLAMP (to, (gdouble) ((gint) _tmp0_), (gdouble) ((gint) _tmp1_));
	_tmp2_ = gala_gesture_controller_get_target (self);
	_tmp3_ = _tmp2_;
	_tmp4_ = self->priv->_action;
	gala_gesture_target_propagate ((GalaGestureTarget*) _tmp3_, GALA_GESTURE_TARGET_UPDATE_TYPE_COMMIT, _tmp4_, clamped_to);
	_tmp5_ = gala_gesture_controller_get_progress (self);
	_tmp6_ = _tmp5_;
	if (_tmp6_ == to) {
		gala_gesture_controller_finished (self, TRUE);
		return;
	}
	if (!meta_prefs_get_gnome_animations ()) {
		gala_gesture_controller_set_progress (self, clamped_to);
		gala_gesture_controller_finished (self, TRUE);
		return;
	}
	_tmp7_ = gala_gesture_controller_get_target (self);
	_tmp8_ = _tmp7_;
	_tmp9_ = gala_root_target_get_actor (_tmp8_);
	_tmp10_ = _tmp9_;
	_tmp11_ = gala_gesture_controller_get_progress (self);
	_tmp12_ = _tmp11_;
	_tmp13_ = gala_spring_timeline_new (_tmp10_, _tmp12_, clamped_to, velocity, (gdouble) 1, (gdouble) 1, (gdouble) 500);
	spring = _tmp13_;
	_tmp14_ = spring;
	g_signal_connect_object (_tmp14_, "progress", (GCallback) ___lambda22__gala_spring_timeline_progress, self, 0);
	_tmp15_ = spring;
	g_signal_connect_object ((ClutterTimeline*) _tmp15_, "stopped", (GCallback) _gala_gesture_controller_finished_clutter_timeline_stopped, self, G_CONNECT_AFTER);
	_tmp16_ = spring;
	_tmp17_ = _g_object_ref0 (_tmp16_);
	_g_object_unref0 (self->priv->timeline);
	self->priv->timeline = _tmp17_;
	_g_object_unref0 (spring);
}

static void
gala_gesture_controller_finished (GalaGestureController* self,
                                  gboolean is_finished)
{
	GalaRootTarget* _tmp0_;
	GalaRootTarget* _tmp1_;
	GalaGestureAction _tmp2_;
	gdouble _tmp3_;
	gdouble _tmp4_;
	g_return_if_fail (self != NULL);
	_vala_return_if_fail (is_finished, "is_finished");
	_tmp0_ = gala_gesture_controller_get_target (self);
	_tmp1_ = _tmp0_;
	_tmp2_ = self->priv->_action;
	_tmp3_ = gala_gesture_controller_get_progress (self);
	_tmp4_ = _tmp3_;
	gala_gesture_target_propagate ((GalaGestureTarget*) _tmp1_, GALA_GESTURE_TARGET_UPDATE_TYPE_END, _tmp2_, _tmp4_);
	_g_object_unref0 (self->priv->timeline);
	self->priv->timeline = NULL;
}

/**
     * Animates to the given progress value.
     * If the gesture is currently recognizing, it will do nothing.
     * If that's not what you want, you should call {@link cancel_gesture} first.
     * If you don't want animation but an immediate jump, you should set {@link progress} directly.
     */
void
gala_gesture_controller_goto (GalaGestureController* self,
                              gdouble to)
{
	gdouble clamped_to = 0.0;
	gdouble _tmp0_;
	gdouble _tmp1_;
	gboolean _tmp2_ = FALSE;
	gboolean _tmp3_ = FALSE;
	gdouble _tmp4_;
	gdouble _tmp5_;
	gint _tmp12_ = 0;
	gdouble _tmp13_;
	gdouble _tmp14_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_overshoot_lower_clamp;
	_tmp1_ = self->priv->_overshoot_upper_clamp;
	clamped_to = CLAMP (to, (gdouble) ((gint) _tmp0_), (gdouble) ((gint) _tmp1_));
	_tmp4_ = gala_gesture_controller_get_progress (self);
	_tmp5_ = _tmp4_;
	if (_tmp5_ == to) {
		_tmp3_ = TRUE;
	} else {
		gboolean _tmp6_;
		_tmp6_ = self->priv->_recognizing;
		_tmp3_ = _tmp6_;
	}
	if (_tmp3_) {
		_tmp2_ = TRUE;
	} else {
		gboolean _tmp7_ = FALSE;
		GalaSpringTimeline* _tmp8_;
		_tmp8_ = self->priv->timeline;
		if (_tmp8_ != NULL) {
			GalaSpringTimeline* _tmp9_;
			gdouble _tmp10_;
			gdouble _tmp11_;
			_tmp9_ = self->priv->timeline;
			_tmp10_ = gala_spring_timeline_get_value_to (_tmp9_);
			_tmp11_ = _tmp10_;
			_tmp7_ = clamped_to == _tmp11_;
		} else {
			_tmp7_ = FALSE;
		}
		_tmp2_ = _tmp7_;
	}
	if (_tmp2_) {
		return;
	}
	gala_gesture_controller_prepare (self);
	_tmp13_ = gala_gesture_controller_get_progress (self);
	_tmp14_ = _tmp13_;
	if (to > _tmp14_) {
		_tmp12_ = 1;
	} else {
		_tmp12_ = -1;
	}
	gala_gesture_controller_finish (self, (gdouble) (_tmp12_ * 1), to);
}

void
gala_gesture_controller_cancel_gesture (GalaGestureController* self)
{
	gboolean _tmp0_;
	g_return_if_fail (self != NULL);
	_tmp0_ = self->priv->_recognizing;
	if (_tmp0_) {
		GalaGestureBackend* _tmp1_;
		_tmp1_ = self->priv->recognizing_backend;
		gala_gesture_backend_cancel_gesture (_tmp1_);
		gala_gesture_controller_gesture_end (self, self->priv->previous_percentage, self->priv->previous_time);
	}
}

GalaGestureAction
gala_gesture_controller_get_action (GalaGestureController* self)
{
	GalaGestureAction result;
	g_return_val_if_fail (self != NULL, 0);
	result = self->priv->_action;
	return result;
}

static void
gala_gesture_controller_set_action (GalaGestureController* self,
                                    GalaGestureAction value)
{
	GalaGestureAction old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_gesture_controller_get_action (self);
	if (old_value != value) {
		self->priv->_action = value;
		g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_ACTION_PROPERTY]);
	}
}

GalaRootTarget*
gala_gesture_controller_get_target (GalaGestureController* self)
{
	GalaRootTarget* result;
	GalaRootTarget* _tmp0_;
	g_return_val_if_fail (self != NULL, NULL);
	_tmp0_ = self->priv->_target;
	result = _tmp0_;
	return result;
}

static void
gala_gesture_controller_set_target (GalaGestureController* self,
                                    GalaRootTarget* value)
{
	GalaRootTarget* _tmp0_;
	GalaGestureAction _tmp1_;
	gdouble _tmp2_;
	gdouble _tmp3_;
	g_return_if_fail (self != NULL);
	self->priv->_target = value;
	_tmp0_ = self->priv->_target;
	_tmp1_ = self->priv->_action;
	_tmp2_ = gala_gesture_controller_get_progress (self);
	_tmp3_ = _tmp2_;
	gala_gesture_target_propagate ((GalaGestureTarget*) _tmp0_, GALA_GESTURE_TARGET_UPDATE_TYPE_UPDATE, _tmp1_, _tmp3_);
	g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_TARGET_PROPERTY]);
}

gdouble
gala_gesture_controller_get_distance (GalaGestureController* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_distance;
	return result;
}

void
gala_gesture_controller_set_distance (GalaGestureController* self,
                                      gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_gesture_controller_get_distance (self);
	if (old_value != value) {
		self->priv->_distance = value;
		g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_DISTANCE_PROPERTY]);
	}
}

gdouble
gala_gesture_controller_get_overshoot_lower_clamp (GalaGestureController* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_overshoot_lower_clamp;
	return result;
}

void
gala_gesture_controller_set_overshoot_lower_clamp (GalaGestureController* self,
                                                   gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_gesture_controller_get_overshoot_lower_clamp (self);
	if (old_value != value) {
		self->priv->_overshoot_lower_clamp = value;
		g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_OVERSHOOT_LOWER_CLAMP_PROPERTY]);
	}
}

gdouble
gala_gesture_controller_get_overshoot_upper_clamp (GalaGestureController* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_overshoot_upper_clamp;
	return result;
}

void
gala_gesture_controller_set_overshoot_upper_clamp (GalaGestureController* self,
                                                   gdouble value)
{
	gdouble old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_gesture_controller_get_overshoot_upper_clamp (self);
	if (old_value != value) {
		self->priv->_overshoot_upper_clamp = value;
		g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_OVERSHOOT_UPPER_CLAMP_PROPERTY]);
	}
}

gboolean
gala_gesture_controller_get_follow_natural_scroll (GalaGestureController* self)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	result = self->priv->_follow_natural_scroll;
	return result;
}

void
gala_gesture_controller_set_follow_natural_scroll (GalaGestureController* self,
                                                   gboolean value)
{
	gboolean old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_gesture_controller_get_follow_natural_scroll (self);
	if (old_value != value) {
		self->priv->_follow_natural_scroll = value;
		g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_FOLLOW_NATURAL_SCROLL_PROPERTY]);
	}
}

gboolean
gala_gesture_controller_get_snap (GalaGestureController* self)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	result = self->priv->_snap;
	return result;
}

void
gala_gesture_controller_set_snap (GalaGestureController* self,
                                  gboolean value)
{
	gboolean old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_gesture_controller_get_snap (self);
	if (old_value != value) {
		self->priv->_snap = value;
		g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_SNAP_PROPERTY]);
	}
}

gdouble
gala_gesture_controller_get_progress (GalaGestureController* self)
{
	gdouble result;
	g_return_val_if_fail (self != NULL, 0.0);
	result = self->priv->_progress;
	return result;
}

void
gala_gesture_controller_set_progress (GalaGestureController* self,
                                      gdouble value)
{
	GalaRootTarget* _tmp0_ = NULL;
	GalaRootTarget* _tmp1_;
	GalaRootTarget* _tmp2_;
	g_return_if_fail (self != NULL);
	self->priv->_progress = value;
	_tmp1_ = gala_gesture_controller_get_target (self);
	_tmp2_ = _tmp1_;
	_tmp0_ = _tmp2_;
	if (_tmp0_ != NULL) {
		GalaGestureAction _tmp3_;
		_tmp3_ = self->priv->_action;
		gala_gesture_target_propagate ((GalaGestureTarget*) _tmp0_, GALA_GESTURE_TARGET_UPDATE_TYPE_UPDATE, _tmp3_, value);
	}
	g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_PROGRESS_PROPERTY]);
}

gboolean
gala_gesture_controller_get_enabled (GalaGestureController* self)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	result = self->priv->_enabled;
	return result;
}

void
gala_gesture_controller_set_enabled (GalaGestureController* self,
                                     gboolean value)
{
	g_return_if_fail (self != NULL);
	gala_gesture_controller_cancel_gesture (self);
	self->priv->_enabled = value;
	g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_ENABLED_PROPERTY]);
}

gboolean
gala_gesture_controller_get_recognizing (GalaGestureController* self)
{
	gboolean result;
	g_return_val_if_fail (self != NULL, FALSE);
	result = self->priv->_recognizing;
	return result;
}

static void
gala_gesture_controller_set_recognizing (GalaGestureController* self,
                                         gboolean value)
{
	gboolean old_value;
	g_return_if_fail (self != NULL);
	old_value = gala_gesture_controller_get_recognizing (self);
	if (old_value != value) {
		self->priv->_recognizing = value;
		g_object_notify_by_pspec ((GObject *) self, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_RECOGNIZING_PROPERTY]);
	}
}

static GObject *
gala_gesture_controller_constructor (GType type,
                                     guint n_construct_properties,
                                     GObjectConstructParam * construct_properties)
{
	GObject * obj;
	GObjectClass * parent_class;
	GalaGestureController * self;
	GeeArrayList* _tmp0_;
	GeeArrayList* _tmp1_;
	parent_class = G_OBJECT_CLASS (gala_gesture_controller_parent_class);
	obj = parent_class->constructor (type, n_construct_properties, construct_properties);
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GALA_TYPE_GESTURE_CONTROLLER, GalaGestureController);
	_tmp0_ = gee_array_list_new (GALA_TYPE_GESTURE_BACKEND, (GBoxedCopyFunc) g_object_ref, (GDestroyNotify) g_object_unref, NULL, NULL, NULL);
	_g_object_unref0 (self->priv->backends);
	self->priv->backends = (GeeList*) _tmp0_;
	_tmp1_ = gee_array_list_new (GALA_TYPE_GESTURE_TRIGGER, (GBoxedCopyFunc) g_object_ref, (GDestroyNotify) g_object_unref, NULL, NULL, NULL);
	_g_object_unref0 (self->priv->triggers);
	self->priv->triggers = (GeeList*) _tmp1_;
	return obj;
}

static void
gala_gesture_controller_class_init (GalaGestureControllerClass * klass,
                                    gpointer klass_data)
{
	gala_gesture_controller_parent_class = g_type_class_peek_parent (klass);
	g_type_class_adjust_private_offset (klass, &GalaGestureController_private_offset);
	G_OBJECT_CLASS (klass)->get_property = _vala_gala_gesture_controller_get_property;
	G_OBJECT_CLASS (klass)->set_property = _vala_gala_gesture_controller_set_property;
	G_OBJECT_CLASS (klass)->constructor = gala_gesture_controller_constructor;
	G_OBJECT_CLASS (klass)->finalize = gala_gesture_controller_finalize;
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_ACTION_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_ACTION_PROPERTY] = g_param_spec_enum ("action", "action", "action", GALA_TYPE_GESTURE_ACTION, 0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_TARGET_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_TARGET_PROPERTY] = g_param_spec_object ("target", "target", "target", GALA_TYPE_ROOT_TARGET, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_DISTANCE_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_DISTANCE_PROPERTY] = g_param_spec_double ("distance", "distance", "distance", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_OVERSHOOT_LOWER_CLAMP_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_OVERSHOOT_LOWER_CLAMP_PROPERTY] = g_param_spec_double ("overshoot-lower-clamp", "overshoot-lower-clamp", "overshoot-lower-clamp", -G_MAXDOUBLE, G_MAXDOUBLE, 0., G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_OVERSHOOT_UPPER_CLAMP_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_OVERSHOOT_UPPER_CLAMP_PROPERTY] = g_param_spec_double ("overshoot-upper-clamp", "overshoot-upper-clamp", "overshoot-upper-clamp", -G_MAXDOUBLE, G_MAXDOUBLE, 1., G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_FOLLOW_NATURAL_SCROLL_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_FOLLOW_NATURAL_SCROLL_PROPERTY] = g_param_spec_boolean ("follow-natural-scroll", "follow-natural-scroll", "follow-natural-scroll", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	/**
	     * When disabled gesture progress will stay where the gesture ended and not snap to full integers values.
	     */
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_SNAP_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_SNAP_PROPERTY] = g_param_spec_boolean ("snap", "snap", "snap", TRUE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_PROGRESS_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_PROGRESS_PROPERTY] = g_param_spec_double ("progress", "progress", "progress", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_ENABLED_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_ENABLED_PROPERTY] = g_param_spec_boolean ("enabled", "enabled", "enabled", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE | G_PARAM_WRITABLE));
	g_object_class_install_property (G_OBJECT_CLASS (klass), GALA_GESTURE_CONTROLLER_RECOGNIZING_PROPERTY, gala_gesture_controller_properties[GALA_GESTURE_CONTROLLER_RECOGNIZING_PROPERTY] = g_param_spec_boolean ("recognizing", "recognizing", "recognizing", FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
}

static void
gala_gesture_controller_instance_init (GalaGestureController * self,
                                       gpointer klass)
{
	self->priv = gala_gesture_controller_get_instance_private (self);
	self->priv->_overshoot_lower_clamp = 0.;
	self->priv->_overshoot_upper_clamp = 1.;
	self->priv->_follow_natural_scroll = FALSE;
	self->priv->_snap = TRUE;
	self->priv->_progress = (gdouble) 0;
	self->priv->_enabled = TRUE;
}

static void
gala_gesture_controller_finalize (GObject * obj)
{
	GalaGestureController * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (obj, GALA_TYPE_GESTURE_CONTROLLER, GalaGestureController);
	_g_object_unref0 (self->priv->backends);
	_g_object_unref0 (self->priv->triggers);
	_g_object_unref0 (self->priv->recognizing_backend);
	_g_object_unref0 (self->priv->timeline);
	G_OBJECT_CLASS (gala_gesture_controller_parent_class)->finalize (obj);
}

/**
 * The class responsible for handling gestures and updating the target. It has a persistent
 * double progress that is either updated by a gesture that is configured with the given
 * {@link GestureAction} from various backends (see the enable_* methods) or manually
 * by calling {@link goto} or setting {@link progress} directly.
 * You shouldn't connect a notify to the progress directly though, but rather use a
 * {@link GestureTarget} implementation.
 * The {@link progress} can be seen as representing the state that the UI the gesture affects
 * is currently in (e.g. 0 for multitasking view closed, 1 for it opened, or 0 for first workspace,
 * -1 for second, -2 for third, etc.). Therefore the progress often needs boundaries which can be
 * set with {@link overshoot_lower_clamp} and {@link overshoot_upper_clamp}. If the values are integers
 * it will be a hard boundary, if they are fractional it will slow the gesture progress when over the
 * limit simulating a kind of spring that pushes against it.
 * Note that the progress snaps to full integer values after a gesture ends.
 * Events are always shared between all GestureControllers in the same group (except for the group NONE).
 * This means that two gestures that can be done in one motion (e.g. horizontal and vertical swipe)
 * can be done simultaneously if each of two GestureControllers in the same group handle one of
 * the gestures.
 */
 G_GNUC_NO_INLINE static GType
gala_gesture_controller_get_type_once (void)
{
	static const GTypeInfo g_define_type_info = { sizeof (GalaGestureControllerClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) gala_gesture_controller_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (GalaGestureController), 0, (GInstanceInitFunc) gala_gesture_controller_instance_init, NULL };
	GType gala_gesture_controller_type_id;
	gala_gesture_controller_type_id = g_type_register_static (G_TYPE_OBJECT, "GalaGestureController", &g_define_type_info, 0);
	GalaGestureController_private_offset = g_type_add_instance_private (gala_gesture_controller_type_id, sizeof (GalaGestureControllerPrivate));
	return gala_gesture_controller_type_id;
}

GType
gala_gesture_controller_get_type (void)
{
	static gsize gala_gesture_controller_type_id__once = 0;
	if (g_once_init_enter (&gala_gesture_controller_type_id__once)) {
		GType gala_gesture_controller_type_id;
		gala_gesture_controller_type_id = gala_gesture_controller_get_type_once ();
		g_once_init_leave (&gala_gesture_controller_type_id__once, gala_gesture_controller_type_id);
	}
	return gala_gesture_controller_type_id__once;
}

static void
_vala_gala_gesture_controller_get_property (GObject * object,
                                            guint property_id,
                                            GValue * value,
                                            GParamSpec * pspec)
{
	GalaGestureController * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GALA_TYPE_GESTURE_CONTROLLER, GalaGestureController);
	switch (property_id) {
		case GALA_GESTURE_CONTROLLER_ACTION_PROPERTY:
		g_value_set_enum (value, gala_gesture_controller_get_action (self));
		break;
		case GALA_GESTURE_CONTROLLER_TARGET_PROPERTY:
		g_value_set_object (value, gala_gesture_controller_get_target (self));
		break;
		case GALA_GESTURE_CONTROLLER_DISTANCE_PROPERTY:
		g_value_set_double (value, gala_gesture_controller_get_distance (self));
		break;
		case GALA_GESTURE_CONTROLLER_OVERSHOOT_LOWER_CLAMP_PROPERTY:
		g_value_set_double (value, gala_gesture_controller_get_overshoot_lower_clamp (self));
		break;
		case GALA_GESTURE_CONTROLLER_OVERSHOOT_UPPER_CLAMP_PROPERTY:
		g_value_set_double (value, gala_gesture_controller_get_overshoot_upper_clamp (self));
		break;
		case GALA_GESTURE_CONTROLLER_FOLLOW_NATURAL_SCROLL_PROPERTY:
		g_value_set_boolean (value, gala_gesture_controller_get_follow_natural_scroll (self));
		break;
		case GALA_GESTURE_CONTROLLER_SNAP_PROPERTY:
		g_value_set_boolean (value, gala_gesture_controller_get_snap (self));
		break;
		case GALA_GESTURE_CONTROLLER_PROGRESS_PROPERTY:
		g_value_set_double (value, gala_gesture_controller_get_progress (self));
		break;
		case GALA_GESTURE_CONTROLLER_ENABLED_PROPERTY:
		g_value_set_boolean (value, gala_gesture_controller_get_enabled (self));
		break;
		case GALA_GESTURE_CONTROLLER_RECOGNIZING_PROPERTY:
		g_value_set_boolean (value, gala_gesture_controller_get_recognizing (self));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

static void
_vala_gala_gesture_controller_set_property (GObject * object,
                                            guint property_id,
                                            const GValue * value,
                                            GParamSpec * pspec)
{
	GalaGestureController * self;
	self = G_TYPE_CHECK_INSTANCE_CAST (object, GALA_TYPE_GESTURE_CONTROLLER, GalaGestureController);
	switch (property_id) {
		case GALA_GESTURE_CONTROLLER_ACTION_PROPERTY:
		gala_gesture_controller_set_action (self, g_value_get_enum (value));
		break;
		case GALA_GESTURE_CONTROLLER_TARGET_PROPERTY:
		gala_gesture_controller_set_target (self, g_value_get_object (value));
		break;
		case GALA_GESTURE_CONTROLLER_DISTANCE_PROPERTY:
		gala_gesture_controller_set_distance (self, g_value_get_double (value));
		break;
		case GALA_GESTURE_CONTROLLER_OVERSHOOT_LOWER_CLAMP_PROPERTY:
		gala_gesture_controller_set_overshoot_lower_clamp (self, g_value_get_double (value));
		break;
		case GALA_GESTURE_CONTROLLER_OVERSHOOT_UPPER_CLAMP_PROPERTY:
		gala_gesture_controller_set_overshoot_upper_clamp (self, g_value_get_double (value));
		break;
		case GALA_GESTURE_CONTROLLER_FOLLOW_NATURAL_SCROLL_PROPERTY:
		gala_gesture_controller_set_follow_natural_scroll (self, g_value_get_boolean (value));
		break;
		case GALA_GESTURE_CONTROLLER_SNAP_PROPERTY:
		gala_gesture_controller_set_snap (self, g_value_get_boolean (value));
		break;
		case GALA_GESTURE_CONTROLLER_PROGRESS_PROPERTY:
		gala_gesture_controller_set_progress (self, g_value_get_double (value));
		break;
		case GALA_GESTURE_CONTROLLER_ENABLED_PROPERTY:
		gala_gesture_controller_set_enabled (self, g_value_get_boolean (value));
		break;
		case GALA_GESTURE_CONTROLLER_RECOGNIZING_PROPERTY:
		gala_gesture_controller_set_recognizing (self, g_value_get_boolean (value));
		break;
		default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
		break;
	}
}

