Compare commits

...

25 Commits

Author SHA1 Message Date
Benjamin Otte
31363bea06 win32: Fix compiler warning 2012-03-14 19:40:15 +01:00
Benjamin Otte
2bf2b5df5f testgestures: Update for gestures 2012-03-14 19:32:56 +01:00
Benjamin Otte
55421f7fed swipe: Move to GtkGesture 2012-03-14 19:32:56 +01:00
Benjamin Otte
ca5b9aa001 pinchpan: Move to GtkGesture 2012-03-14 19:32:56 +01:00
Benjamin Otte
b469025153 API: gtk: Add GtkGesture
GtkGesture is a GtkEventTracker that knows about sequences and sends
information about them.
2012-03-14 19:32:56 +01:00
Benjamin Otte
c7f55213ee eventtracker: Add some private APIs for use by gestures 2012-03-14 19:32:56 +01:00
Benjamin Otte
7749195e0b reftests: Add a test for specificity of @import 2012-03-14 19:32:56 +01:00
Benjamin Otte
a28f99bf40 tests: Update testgestures example for new widget APIs
We can now use gtk_widget_add_recognizer()
2012-03-14 19:32:55 +01:00
Benjamin Otte
699a315ff8 gdk: Add debug printout for adding axes 2012-03-14 19:32:55 +01:00
Benjamin Otte
7914ce8231 API: widget: Change recognizer addition/removal API
Instead of addition/removal/inspection per class, there's now just
addition per class and addition/removal/inspection per widgets.

Widgets inherit the class recognizers on init.
2012-03-14 19:32:55 +01:00
Benjamin Otte
39b9acf56d tests: Update testgestures example for pinch/pan gesture.
FIXME: This is a hack.
2012-03-14 19:32:55 +01:00
Benjamin Otte
4f2a7bb96d API: Add a pinch/pan/rotate gesture
For lack of a better name, it's called GtkPinchPanGesture. Suggest a
better name and I'll change it.
2012-03-14 19:32:55 +01:00
Benjamin Otte
e89f76a944 eventtracker: Redo list implementation
Instead of using a GQueue, use an inline list.

This way, we can figure out the next/previous tracker from the current
tracker, which may come in useful later.
2012-03-14 19:32:55 +01:00
Benjamin Otte
20dd5c5b43 tests: Add a simple test for gestures 2012-03-14 19:32:55 +01:00
Benjamin Otte
61c1737cde API: gtk: Add a swipe gesture
First event recognizer.
2012-03-14 19:32:55 +01:00
Benjamin Otte
2640918761 gtk: Add sequence trackers
Sequence trackers are a private object that hides the fact that some
event sequences are provided by mice, some by touchscreens and some by
touchpads. It just provides an API based on pixels.
2012-03-14 19:32:55 +01:00
Benjamin Otte
1b48a544e5 gtk: Invoke trackers and recognizers
Adds the basic plumbing necessary to ensure recognizers and trackers get
invoked.
2012-03-14 19:32:55 +01:00
Benjamin Otte
6a14c755c8 API: widget: Add API for adding recognizers
Apart from adding and removing them, nothing can be done with them.
2012-03-14 19:32:55 +01:00
Benjamin Otte
dd499e9829 docs: Add docs for event recognizers 2012-03-14 19:32:55 +01:00
Benjamin Otte
f08fb83b21 API: Add the basics of the event recognizer implementation 2012-03-14 19:32:55 +01:00
Benjamin Otte
d1975edb6a API: gdk: Add GdkAxisUse entries for relative axes
Those are necessary for touchpads.
2012-03-14 19:32:55 +01:00
Benjamin Otte
a0ab7cc207 x11: Use the new event sequence to store axis values
This way, we can put the correct number into the event.touch.axes member
instead of random 0s when values didn't change.

Somebody should do the same thing for buttons.
2012-03-14 19:32:55 +01:00
Benjamin Otte
4da18923c5 gdk: Make event sequences real objects
So far this fact is hidden from the implementation. The usefulness of
this change will soon become apparent.
2012-03-14 19:32:54 +01:00
Benjamin Otte
d3cdf494d9 gdk: Move GdkEventSequence declaration
Put it in gdktypes.h - Makes a bunch of future features easier.
2012-03-14 19:32:54 +01:00
Benjamin Otte
82838a2056 API: gdk: Add gdk_device_get_axis_label() 2012-03-14 19:32:54 +01:00
55 changed files with 3935 additions and 35 deletions

View File

@@ -691,6 +691,7 @@ gdk_device_set_key
gdk_device_get_key
gdk_device_set_axis_use
gdk_device_get_axis_use
gdk_device_get_axis_label
gdk_device_get_associated_device
gdk_device_list_slave_devices
gdk_device_get_device_type

View File

@@ -0,0 +1,103 @@
<?xml version="1.0"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<chapter id="event-handling">
<title>Event handling in GTK+ 3</title>
<para>
In version 3.6, GTK+ has overhauled the way widgets handle input events
considerably. The main motivation for this has been the more complex
interaction models used by modern toolkitts. In particular, enabling
all the behaviors people expect from multitouch support was guiding the
design.
</para>
<para>
The principles outlined in this chapter are only relevant for people
that want to implement their own #GtkWidgets. It is not necessary that
you understand the concepts here when all you want to do is use existing
widgets to create your own application.
</para>
<section>
<title>The high-level view</title>
<para>
FIXME
</para>
<para>
The GTK event system is a cooperative event handling system. This means
that event recognizers need not know on their own if they should
recognize an event, but they communicate with other recognizers about
the process.
</para>
</section>
<section>
<title>Setting up your widget</title>
<section>
<title>Using GtkBuilder</title>
<para>
FIXME (with examples!)
</para>
</section>
<section>
<title>Manual addition of event recognizers</title>
<para>
FIXME (with examples!)
</para>
</section>
</section>
<section>
<title>Event flow</title>
<section>
<title>Lifetime of a #GtkEventTracker</title>
<para>
FIXME
</para>
<section>
<section>
<title>Flow of a #GdkEvent through the event machinery</title>
<para>
FIXME (make sure to not be too specific, so we can still change stuff later)
</para>
<section>
</section>
<section>
<title>Writing your own event recognizers</title>
<para>
The GTK developers generally discourage the writing of new event recognizers.
We are trying to provide a consistent feel to GTK applications and with all
the included event recognizers we think almost all the functionality needed
for event handling should be there for you to use.
Of course, every rule has its exceptions or you might just feel adventurous.
so should you see yourself in a situation where you need to write your own
event recognizers, here are some hints on how to do it.
</para>
<section>
<title>FIXME</title>
<para>
FIXME
</para>
<section>
</section>
</chapter>

View File

@@ -271,6 +271,13 @@
<xi:include href="xml/gtkscrollable.xml" />
</chapter>
<chapter id="Events">
<title>Event handling</title>
<xi:include href="xml/event-handling.xml" />
<xi:include href="xml/gtkeventrecognizer.xml" />
<xi:include href="xml/gtkeventtracker.xml" />
</chapter>
<chapter id="Printing">
<title>Printing</title>
<xi:include href="xml/gtkprintoperation.xml" />

View File

@@ -101,6 +101,7 @@ gdk_private_headers = \
gdkdisplaymanagerprivate.h \
gdkdisplayprivate.h \
gdkdndprivate.h \
gdkeventsequenceprivate.h \
gdkscreenprivate.h \
gdkinternals.h \
gdkintl.h \
@@ -121,6 +122,7 @@ gdk_c_sources = \
gdkdisplaymanager.c \
gdkdnd.c \
gdkevents.c \
gdkeventsequence.c \
gdkglobals.c \
gdkkeys.c \
gdkkeyuni.c \

View File

@@ -93,8 +93,8 @@ gdk_broadway_device_init (GdkBroadwayDevice *device_core)
device = GDK_DEVICE (device_core);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_Y, 0, 0, 1);
}
static gboolean

View File

@@ -47,6 +47,7 @@ gdk_cursor_unref
gdk_device_free_history
gdk_device_get_associated_device
gdk_device_get_axis
gdk_device_get_axis_label
gdk_device_get_axis_use
gdk_device_get_axis_value
gdk_device_get_device_type

View File

@@ -21,6 +21,7 @@
#include "gdkdeviceprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkeventsequenceprivate.h"
#include "gdkinternals.h"
#include "gdkintl.h"
@@ -43,6 +44,7 @@ typedef struct _GdkAxisInfo GdkAxisInfo;
struct _GdkAxisInfo
{
GdkAtom label;
gchar *label_string;
GdkAxisUse use;
gdouble min_axis;
@@ -255,16 +257,26 @@ gdk_device_class_init (GdkDeviceClass *klass)
G_TYPE_NONE, 0);
}
static void
gdk_axis_info_clear (gpointer data)
{
GdkAxisInfo *info = data;
g_free (info->label_string);
}
static void
gdk_device_init (GdkDevice *device)
{
device->axes = g_array_new (FALSE, TRUE, sizeof (GdkAxisInfo));
g_array_set_clear_func (device->axes, gdk_axis_info_clear);
}
static void
gdk_device_dispose (GObject *object)
{
GdkDevice *device = GDK_DEVICE (object);
GSList *list;
if (device->type == GDK_DEVICE_TYPE_SLAVE)
_gdk_device_remove_slave (device->associated, device);
@@ -278,6 +290,18 @@ gdk_device_dispose (GObject *object)
device->associated = NULL;
}
for (list = device->sequences; list; list = list->next)
{
GdkEventSequence *sequence = list->data;
/* Set device to NULL in advance so that the unreffing doesn't
* modify the list we iterate over */
sequence->device = NULL;
gdk_event_sequence_unref (sequence);
}
g_slist_free (device->sequences);
device->sequences = NULL;
if (device->axes)
{
g_array_free (device->axes, TRUE);
@@ -770,6 +794,39 @@ gdk_device_set_key (GdkDevice *device,
device->keys[index_].modifiers = modifiers;
}
/**
* gdk_device_get_axis_label:
* @device: a pointer #GdkDevice.
* @index_: the index of the axis.
*
* Returns the label for the axis. If it exists, the label of
* an axis is a string identifying the axis. Labels for the same
* types of axes may differ between devices and platforms. Try to use
* gdk_device_get_axis_use() if possible.
*
* This function is useful as a debugging help. It should never
* be presented to users.
*
* Returns: a string describing the label of the axis or %NULL
* if the axis has no label.
*
* Since: 3.6
**/
const char *
gdk_device_get_axis_label (GdkDevice *device,
guint index_)
{
GdkAxisInfo *info;
g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
g_return_val_if_fail (index_ < device->axes->len, NULL);
info = &g_array_index (device->axes, GdkAxisInfo, index_);
return info->label_string;
}
/**
* gdk_device_get_axis_use:
* @device: a pointer #GdkDevice.
@@ -1329,6 +1386,7 @@ _gdk_device_reset_axes (GdkDevice *device)
guint
_gdk_device_add_axis (GdkDevice *device,
GdkAtom label_atom,
const char *label_string,
GdkAxisUse use,
gdouble min_value,
gdouble max_value,
@@ -1337,8 +1395,12 @@ _gdk_device_add_axis (GdkDevice *device,
GdkAxisInfo axis_info;
guint pos;
GDK_NOTE (INPUT, g_print ("Adding axis '%s' with use %d for range [%g, %g] with %gunits/m\n",
label_string, use, min_value, max_value, resolution));
axis_info.use = use;
axis_info.label = label_atom;
axis_info.label_string = g_strdup (label_string);
axis_info.min_value = min_value;
axis_info.max_value = max_value;
axis_info.resolution = resolution;

View File

@@ -88,6 +88,10 @@ typedef enum
* @GDK_AXIS_XTILT: the axis is used for x tilt information.
* @GDK_AXIS_YTILT: the axis is used for y tilt information.
* @GDK_AXIS_WHEEL: the axis is used for wheel information.
* @GDK_AXIS_X_RELATIVE: the axis used to describe relative movement along
* the x axis. Useful for tracking movement on %GDK_SOURCE_TOUCHPAD devices.
* @GDK_AXIS_Y_RELATIVE: the axis used to describe relative movement along
* the y axis. Useful for tracking movement on %GDK_SOURCE_TOUCHPAD devices.
* @GDK_AXIS_LAST: a constant equal to the numerically highest axis value.
*
* An enumeration describing the way in which a device
@@ -103,6 +107,8 @@ typedef enum
GDK_AXIS_XTILT,
GDK_AXIS_YTILT,
GDK_AXIS_WHEEL,
GDK_AXIS_X_RELATIVE,
GDK_AXIS_Y_RELATIVE,
GDK_AXIS_LAST
} GdkAxisUse;
@@ -163,6 +169,8 @@ void gdk_device_set_key (GdkDevice *device,
guint keyval,
GdkModifierType modifiers);
const char * gdk_device_get_axis_label(GdkDevice *device,
guint index_);
GdkAxisUse gdk_device_get_axis_use (GdkDevice *device,
guint index_);
void gdk_device_set_axis_use (GdkDevice *device,

View File

@@ -56,6 +56,7 @@ struct _GdkDevice
GList *slaves;
GdkDeviceType type;
GArray *axes;
GSList *sequences;
};
struct _GdkDeviceClass
@@ -117,6 +118,7 @@ void _gdk_device_set_associated_device (GdkDevice *device,
void _gdk_device_reset_axes (GdkDevice *device);
guint _gdk_device_add_axis (GdkDevice *device,
GdkAtom label_atom,
const char *label_string,
GdkAxisUse use,
gdouble min_value,
gdouble max_value,

View File

@@ -26,6 +26,7 @@
#include "gdkinternals.h"
#include "gdkdisplayprivate.h"
#include "gdkeventsequenceprivate.h"
#include <string.h>
#include <math.h>
@@ -600,6 +601,7 @@ gdk_event_copy (const GdkEvent *event)
case GDK_TOUCH_UPDATE:
case GDK_TOUCH_END:
case GDK_TOUCH_CANCEL:
new_event->touch.sequence = gdk_event_sequence_ref (event->touch.sequence);
if (event->touch.axes)
new_event->touch.axes = g_memdup (event->touch.axes,
sizeof (gdouble) * gdk_device_get_n_axes (event->touch.device));
@@ -689,6 +691,7 @@ gdk_event_free (GdkEvent *event)
case GDK_TOUCH_END:
case GDK_TOUCH_CANCEL:
g_free (event->touch.axes);
gdk_event_sequence_unref (event->touch.sequence);
break;
case GDK_EXPOSE:

View File

@@ -144,8 +144,6 @@ typedef struct _GdkEventWindowState GdkEventWindowState;
typedef struct _GdkEventSetting GdkEventSetting;
typedef struct _GdkEventGrabBroken GdkEventGrabBroken;
typedef struct _GdkEventSequence GdkEventSequence;
typedef union _GdkEvent GdkEvent;
/**

85
gdk/gdkeventsequence.c Normal file
View File

@@ -0,0 +1,85 @@
/* gdkeventsequence.h - tracking sequences of events
* Copyright (C) 2012 Red Hat, Inc.
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "gdkeventsequenceprivate.h"
#include "gdkdeviceprivate.h"
/* XXX: Does not return a reference - should we change that? */
GdkEventSequence *
gdk_event_sequence_new (GdkDevice *device,
guint sequence_id)
{
GdkEventSequence *sequence = g_slice_new0 (GdkEventSequence);
/* device owns sequence, so cannot ref device here */
sequence->ref_count = 1;
sequence->device = device;
sequence->sequence_id = sequence_id;
sequence->axes = g_new0 (gdouble, gdk_device_get_n_axes (device));
device->sequences = g_slist_prepend (device->sequences, sequence);
return sequence;
}
GdkEventSequence *
gdk_event_sequence_lookup (GdkDevice *device,
guint sequence_id)
{
GSList *list;
for (list = device->sequences; list; list = list->next)
{
GdkEventSequence *sequence = list->data;
if (sequence->sequence_id == sequence_id)
return sequence;
}
return NULL;
}
GdkEventSequence *
gdk_event_sequence_ref (GdkEventSequence *sequence)
{
sequence->ref_count++;
return sequence;
}
void
gdk_event_sequence_unref (GdkEventSequence *sequence)
{
sequence->ref_count--;
if (sequence->ref_count > 0)
return;
if (sequence->device)
{
GdkDevice *device = sequence->device;
device->sequences = g_slist_remove (device->sequences, sequence);
}
g_free (sequence->axes);
g_slice_free (GdkEventSequence, sequence);
}

View File

@@ -0,0 +1,44 @@
/* gdkeventsequence.h - tracking sequences of events
* Copyright (C) 2012 Red Hat, Inc.
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#ifndef __GDK_EVENT_SEQUENCE_H__
#define __GDK_EVENT_SEQUENCE_H__
#include <gdk/gdktypes.h>
struct _GdkEventSequence {
GdkDevice *device;
guint sequence_id;
guint ref_count;
double *axes;
};
GdkEventSequence * gdk_event_sequence_new (GdkDevice *device,
guint sequence_id);
GdkEventSequence * gdk_event_sequence_lookup (GdkDevice *device,
guint sequence_id);
GdkEventSequence * gdk_event_sequence_ref (GdkEventSequence *sequence);
void gdk_event_sequence_unref (GdkEventSequence *sequence);
#endif /* __GDK_EVENT_SEQUENCE_H__ */

View File

@@ -123,6 +123,7 @@ typedef struct _GdkDragContext GdkDragContext;
typedef struct _GdkDisplayManager GdkDisplayManager;
typedef struct _GdkDeviceManager GdkDeviceManager;
typedef struct _GdkDisplay GdkDisplay;
typedef struct _GdkEventSequence GdkEventSequence;
typedef struct _GdkScreen GdkScreen;
typedef struct _GdkWindow GdkWindow;
typedef struct _GdkKeymap GdkKeymap;

View File

@@ -29,6 +29,7 @@
#include "gdkwindow.h"
#include "gdkeventsequenceprivate.h"
#include "gdkrectangle.h"
#include "gdkinternals.h"
#include "gdkintl.h"
@@ -9483,7 +9484,7 @@ proxy_pointer_event (GdkDisplay *display,
{
event->touch.time = time_;
event->touch.state = state | GDK_BUTTON1_MASK;
event->touch.sequence = source_event->touch.sequence;
event->touch.sequence = gdk_event_sequence_ref (source_event->touch.sequence);
event->touch.emulating_pointer = source_event->touch.emulating_pointer;
convert_toplevel_coords_to_window (event_win,
toplevel_x, toplevel_y,
@@ -9772,7 +9773,7 @@ proxy_button_event (GdkEvent *source_event,
event->touch.device = source_event->touch.device;
event->touch.axes = g_memdup (source_event->touch.axes,
sizeof (gdouble) * gdk_device_get_n_axes (source_event->touch.device));
event->touch.sequence = source_event->touch.sequence;
event->touch.sequence = gdk_event_sequence_ref (source_event->touch.sequence);
event->touch.emulating_pointer = source_event->touch.emulating_pointer;
gdk_event_set_source_device (event, source_device);

View File

@@ -107,8 +107,8 @@ gdk_quartz_device_core_init (GdkQuartzDeviceCore *quartz_device_core)
device = GDK_DEVICE (quartz_device_core);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_Y, 0, 0, 1);
}
static gboolean

View File

@@ -334,8 +334,8 @@ gdk_device_core_init (GdkDeviceCore *device_core)
device = GDK_DEVICE (device_core);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_Y, 0, 0, 1);
}
struct wl_input_device *

View File

@@ -96,8 +96,8 @@ gdk_device_win32_init (GdkDeviceWin32 *device_win32)
device = GDK_DEVICE (device_win32);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_Y, 0, 0, 1);
}
static gboolean

View File

@@ -593,6 +593,7 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
NULL,
GDK_AXIS_X,
axis_x.axMin,
axis_x.axMax,
@@ -604,6 +605,7 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
NULL,
GDK_AXIS_Y,
axis_y.axMin,
axis_y.axMax,
@@ -616,6 +618,7 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
{
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
NULL,
GDK_AXIS_PRESSURE,
axis_npressure.axMin,
axis_npressure.axMax,
@@ -638,6 +641,7 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
*/
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
NULL,
GDK_AXIS_XTILT,
-1000,
1000,
@@ -645,6 +649,7 @@ _gdk_input_wintab_init_check (GdkDeviceManager *_device_manager)
_gdk_device_add_axis (GDK_DEVICE (device),
GDK_NONE,
NULL,
GDK_AXIS_YTILT,
-1000,
1000,

View File

@@ -104,8 +104,8 @@ gdk_x11_device_core_init (GdkX11DeviceCore *device_core)
device = GDK_DEVICE (device_core);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, GDK_AXIS_Y, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_X, 0, 0, 1);
_gdk_device_add_axis (device, GDK_NONE, NULL, GDK_AXIS_Y, 0, 0, 1);
}
static gboolean

View File

@@ -23,6 +23,7 @@
#include "gdkdevicemanagerprivate-core.h"
#include "gdkdeviceprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkeventsequenceprivate.h"
#include "gdkeventtranslator.h"
#include "gdkprivate-x11.h"
#include "gdkintl.h"
@@ -167,7 +168,8 @@ translate_valuator_class (GdkDisplay *display,
static gboolean initialized = FALSE;
static Atom label_atoms [GDK_AXIS_LAST] = { 0 };
GdkAxisUse use = GDK_AXIS_IGNORE;
GdkAtom label;
GdkAtom atom;
const char *label;
gint i;
if (!initialized)
@@ -178,6 +180,8 @@ translate_valuator_class (GdkDisplay *display,
label_atoms [GDK_AXIS_XTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt X");
label_atoms [GDK_AXIS_YTILT] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Tilt Y");
label_atoms [GDK_AXIS_WHEEL] = gdk_x11_get_xatom_by_name_for_display (display, "Abs Wheel");
label_atoms [GDK_AXIS_X_RELATIVE] = gdk_x11_get_xatom_by_name_for_display (display, "Rel X");
label_atoms [GDK_AXIS_Y_RELATIVE] = gdk_x11_get_xatom_by_name_for_display (display, "Rel Y");
initialized = TRUE;
}
@@ -191,11 +195,17 @@ translate_valuator_class (GdkDisplay *display,
}
if (valuator_label != None)
label = gdk_x11_xatom_to_atom_for_display (display, valuator_label);
{
atom = gdk_x11_xatom_to_atom_for_display (display, valuator_label);
label = gdk_x11_get_xatom_name_for_display (display, valuator_label);
}
else
label = GDK_NONE;
{
atom = GDK_NONE;
label = NULL;
}
_gdk_device_add_axis (device, label, use, min, max, resolution);
_gdk_device_add_axis (device, atom, label, use, min, max, resolution);
}
static void
@@ -855,6 +865,7 @@ set_user_time (GdkEvent *event)
static gdouble *
translate_axes (GdkDevice *device,
gdouble *saved_values,
gdouble x,
gdouble y,
GdkWindow *window,
@@ -866,16 +877,22 @@ translate_axes (GdkDevice *device,
g_object_get (device, "n-axes", &n_axes, NULL);
axes = g_new0 (gdouble, n_axes);
axes = g_new (gdouble, n_axes);
vals = valuators->values;
for (i = 0; i < valuators->mask_len * 8; i++)
for (i = 0; i < MIN (valuators->mask_len * 8, n_axes); i++)
{
GdkAxisUse use;
gdouble val;
if (!XIMaskIsSet (valuators->mask, i))
continue;
{
if (saved_values)
axes[i] = saved_values[i];
else
axes[i] = 0.0;
continue;
}
use = gdk_device_get_axis_use (device, i);
val = *vals++;
@@ -898,6 +915,9 @@ translate_axes (GdkDevice *device,
_gdk_device_translate_axis (device, i, val, &axes[i]);
break;
}
if (saved_values)
saved_values[i] = axes[i];
}
return axes;
@@ -1267,6 +1287,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
gdk_event_set_source_device (event, source_device);
event->button.axes = translate_axes (event->button.device,
NULL,
event->button.x,
event->button.y,
event->button.window,
@@ -1368,6 +1389,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
event->motion.is_hint = FALSE;
event->motion.axes = translate_axes (event->motion.device,
NULL,
event->motion.x,
event->motion.y,
event->motion.window,
@@ -1417,7 +1439,22 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
event->touch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
if (ev->evtype == XI_TouchBegin)
{
event->touch.state |= GDK_BUTTON1_MASK;
event->touch.sequence = gdk_event_sequence_new (event->touch.device, xev->detail);
gdk_event_sequence_ref (event->touch.sequence);
}
else
{
/* no ref here, we want the sequence to go away with the event */
event->touch.sequence = gdk_event_sequence_lookup (event->touch.device, xev->detail);
}
event->touch.axes = translate_axes (event->touch.device,
event->touch.sequence->axes,
event->touch.x,
event->touch.y,
event->touch.window,
@@ -1432,13 +1469,6 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
gdk_device_get_axis (device, event->touch.axes, GDK_AXIS_Y, &event->touch.y);
}
event->touch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
if (ev->evtype == XI_TouchBegin)
event->touch.state |= GDK_BUTTON1_MASK;
event->touch.sequence = GUINT_TO_POINTER (xev->detail);
if (xev->flags & XITouchEmulatingPointer)
{
event->touch.emulating_pointer = TRUE;
@@ -1471,7 +1501,6 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
xev->flags & XITouchEmulatingPointer));
event->touch.window = window;
event->touch.sequence = GUINT_TO_POINTER (xev->detail);
event->touch.type = GDK_TOUCH_UPDATE;
event->touch.time = xev->time;
event->touch.x = (gdouble) xev->event_x;
@@ -1486,6 +1515,9 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
GUINT_TO_POINTER (xev->sourceid));
gdk_event_set_source_device (event, source_device);
event->touch.sequence = gdk_event_sequence_lookup (event->touch.device, xev->detail);
gdk_event_sequence_ref (event->touch.sequence);
event->touch.state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
event->touch.state |= GDK_BUTTON1_MASK;
@@ -1497,6 +1529,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
}
event->touch.axes = translate_axes (event->touch.device,
event->touch.sequence->axes,
event->touch.x,
event->touch.y,
event->touch.window,

View File

@@ -237,6 +237,8 @@ gtk_public_h_sources = \
gtkentrycompletion.h \
gtkenums.h \
gtkeventbox.h \
gtkeventrecognizer.h \
gtkeventtracker.h \
gtkexpander.h \
gtkfilechooser.h \
gtkfilechooserbutton.h \
@@ -249,6 +251,8 @@ gtk_public_h_sources = \
gtkfontchooserdialog.h \
gtkfontchooserwidget.h \
gtkframe.h \
gtkgesture.h \
gtkgesturerecognizer.h \
gtkgradient.h \
gtkgrid.h \
gtkiconfactory.h \
@@ -286,6 +290,8 @@ gtk_public_h_sources = \
gtkpagesetup.h \
gtkpaned.h \
gtkpapersize.h \
gtkpinchpangesture.h \
gtkpinchpanrecognizer.h \
gtkplug.h \
gtkprintcontext.h \
gtkprintoperation.h \
@@ -313,6 +319,7 @@ gtk_public_h_sources = \
gtkseparator.h \
gtkseparatormenuitem.h \
gtkseparatortoolitem.h \
gtksequence.h \
gtksettings.h \
gtkshow.h \
gtksizegroup.h \
@@ -326,6 +333,8 @@ gtk_public_h_sources = \
gtkstylecontext.h \
gtkstyleproperties.h \
gtkstyleprovider.h \
gtkswipegesture.h \
gtkswiperecognizer.h \
gtkswitch.h \
gtksymboliccolor.h \
gtktestutils.h \
@@ -486,6 +495,7 @@ gtk_private_h_sources = \
gtksearchengine.h \
gtksearchenginesimple.h \
gtkselectionprivate.h \
gtksequencetrackerprivate.h \
gtksettingsprivate.h \
gtkshadowprivate.h \
gtksizegroup-private.h \
@@ -644,6 +654,8 @@ gtk_base_c_sources = \
gtkentrybuffer.c \
gtkentrycompletion.c \
gtkeventbox.c \
gtkeventrecognizer.c \
gtkeventtracker.c \
gtkexpander.c \
gtkfilechooser.c \
gtkfilechooserbutton.c \
@@ -663,6 +675,8 @@ gtk_base_c_sources = \
gtkfontchooserutils.c \
gtkfontchooserwidget.c \
gtkframe.c \
gtkgesture.c \
gtkgesturerecognizer.c \
gtkgradient.c \
gtkgrid.c \
gtkiconcache.c \
@@ -710,6 +724,8 @@ gtk_base_c_sources = \
gtkpango.c \
gtkpapersize.c \
gtkpathbar.c \
gtkpinchpangesture.c \
gtkpinchpanrecognizer.c \
gtkpressandhold.c \
gtkprintcontext.c \
gtkprintoperation.c \
@@ -745,6 +761,8 @@ gtk_base_c_sources = \
gtkseparator.c \
gtkseparatormenuitem.c \
gtkseparatortoolitem.c \
gtksequence.c \
gtksequencetracker.c \
gtksettings.c \
gtksizegroup.c \
gtksizerequest.c \
@@ -760,6 +778,8 @@ gtk_base_c_sources = \
gtkstyleproperty.c \
gtkstyleprovider.c \
gtkstyleproviderprivate.c \
gtkswipegesture.c \
gtkswiperecognizer.c \
gtkswitch.c \
gtksymboliccolor.c \
gtktestutils.c \

View File

@@ -95,6 +95,8 @@
#include <gtk/gtkentrycompletion.h>
#include <gtk/gtkenums.h>
#include <gtk/gtkeventbox.h>
#include <gtk/gtkeventrecognizer.h>
#include <gtk/gtkeventtracker.h>
#include <gtk/gtkexpander.h>
#include <gtk/gtkfixed.h>
#include <gtk/gtkfilechooser.h>
@@ -107,6 +109,8 @@
#include <gtk/gtkfontchooserdialog.h>
#include <gtk/gtkfontchooserwidget.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkgesture.h>
#include <gtk/gtkgesturerecognizer.h>
#include <gtk/gtkgradient.h>
#include <gtk/gtkgrid.h>
#include <gtk/gtkiconfactory.h>
@@ -143,6 +147,8 @@
#include <gtk/gtkpagesetup.h>
#include <gtk/gtkpapersize.h>
#include <gtk/gtkpaned.h>
#include <gtk/gtkpinchpangesture.h>
#include <gtk/gtkpinchpanrecognizer.h>
#include <gtk/gtkprintcontext.h>
#include <gtk/gtkprintoperation.h>
#include <gtk/gtkprintoperationpreview.h>
@@ -169,6 +175,7 @@
#include <gtk/gtkseparator.h>
#include <gtk/gtkseparatormenuitem.h>
#include <gtk/gtkseparatortoolitem.h>
#include <gtk/gtksequence.h>
#include <gtk/gtksettings.h>
#include <gtk/gtkshow.h>
#include <gtk/gtksizegroup.h>
@@ -181,6 +188,8 @@
#include <gtk/gtkstylecontext.h>
#include <gtk/gtkstyleproperties.h>
#include <gtk/gtkstyleprovider.h>
#include <gtk/gtkswipegesture.h>
#include <gtk/gtkswiperecognizer.h>
#include <gtk/gtkswitch.h>
#include <gtk/gtksymboliccolor.h>
#include <gtk/gtktextattributes.h>

262
gtk/gtkeventrecognizer.c Normal file
View File

@@ -0,0 +1,262 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkeventrecognizer.h"
#include "gtkeventrecognizerprivate.h"
#include "gtkeventtracker.h"
#include "gtkeventtrackerprivate.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtkwidget.h"
/**
* SECTION:gtkeventrecognizer
* @Short_description: Recognizes gestures from events
* @Title: GtkEventRecognizer
* @See_also: #GtkEventTracker
*
* #GtkEventRecoginzer and its subclasses are used for defining the event
* handling behavior of #GtkWidgets.
*
* #GtkEventRecognizer was added in GTK 3.6.
*/
enum {
STARTED,
UPDATED,
FINISHED,
CANCELLED,
/* add more */
LAST_SIGNAL
};
guint signals[LAST_SIGNAL];
G_DEFINE_ABSTRACT_TYPE (GtkEventRecognizer, gtk_event_recognizer, G_TYPE_OBJECT)
static void
gtk_event_recognizer_default_recognize (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event)
{
}
static gboolean
gtk_event_recognizer_default_track (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
GdkEvent *event)
{
return FALSE;
}
static void
gtk_event_recognizer_class_init (GtkEventRecognizerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
klass->tracker_type = GTK_TYPE_EVENT_TRACKER;
klass->recognize = gtk_event_recognizer_default_recognize;
klass->track = gtk_event_recognizer_default_track;
/**
* GtkEventRecognizer::started:
* @recognizer: the recognizer
* @tracker: the tracker that was started
*
* Signals that @tracker has started recognizing an event sequence. Widgets
* using @recognizer may now wish to update transient state based on
* @tracker.
*
* From now on, @recognizer will emit GtkEventRecognizer::updated signals
* for @tracker until either the sequence got cancelled via a
* GtkEventRecognizer::cancelled signal emission or successfully recognized
* with a GtkEventRecognizer::finished signal.
*/
signals[STARTED] =
g_signal_new (I_("started"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkEventRecognizerClass, started),
NULL, NULL,
_gtk_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_EVENT_TRACKER);
/**
* GtkEventRecognizer::updated:
* @recognizer: the recognizer
* @tracker: the tracker that was updated
*
* Signals that @tracker has updated its internal state while recognizing
* an event sequence. Widgets using @recognizer may now wish to update
* transient state based on @tracker.
*/
signals[UPDATED] =
g_signal_new (I_("updated"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkEventRecognizerClass, updated),
NULL, NULL,
_gtk_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_EVENT_TRACKER);
/**
* GtkEventRecognizer::finished:
* @recognizer: the recognizer
* @tracker: the tracker that was finished
*
* Signals that @tracker has successfully recognized an event sequence and
* will now stop processing events or change state. Widgets using @recognizer
* should now update their state based on this event based on the information
* provided by @tracker.
*
* This signal will only be emitted after GtkEventRecognizer::started has
* been emitted for @tracker. It might not ever be emitted if @tracker was
* cancelled and GtkEventRecognizer::cancelled has been emitted instead. After
* this signal has been emitted, no new signals will be emitted for @tracker.
*/
signals[FINISHED] =
g_signal_new (I_("finished"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkEventRecognizerClass, finished),
NULL, NULL,
_gtk_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_EVENT_TRACKER);
/**
* GtkEventRecognizer::cancelled:
* @recognizer: the recognizer
* @tracker: the tracker that was cancelled
*
* Signals that @tracker has been cancelled. It will now stop tracking
* events. A widget should now undo all modifications it did due prior signal
* emissions.
*
* This signal will only be emitted after GtkEventRecognizer::started has
* been emitted for @tracker. If it gets emitted, no other events will be emitted
* for @tracker.
*/
signals[CANCELLED] =
g_signal_new (I_("cancelled"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkEventRecognizerClass, cancelled),
NULL, NULL,
_gtk_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_EVENT_TRACKER);
}
static void
gtk_event_recognizer_init (GtkEventRecognizer *recognizer)
{
}
gint
gtk_event_recognizer_class_get_event_mask (GtkEventRecognizerClass *klass)
{
g_return_val_if_fail (GTK_IS_EVENT_RECOGNIZER_CLASS (klass), 0);
return klass->event_mask;
}
void
gtk_event_recognizer_class_set_event_mask (GtkEventRecognizerClass *klass,
gint event_mask)
{
g_return_if_fail (GTK_IS_EVENT_RECOGNIZER_CLASS (klass));
klass->event_mask = event_mask;
}
GType
gtk_event_recognizer_class_get_tracker_type (GtkEventRecognizerClass *klass)
{
g_return_val_if_fail (GTK_IS_EVENT_RECOGNIZER_CLASS (klass), 0);
return klass->tracker_type;
}
void
gtk_event_recognizer_class_set_tracker_type (GtkEventRecognizerClass *klass,
GType tracker_type)
{
g_return_if_fail (GTK_IS_EVENT_RECOGNIZER_CLASS (klass));
g_return_if_fail (g_type_is_a (tracker_type, klass->tracker_type));
klass->tracker_type = tracker_type;
}
void
gtk_event_recognizer_create_tracker (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event)
{
GtkEventTracker *tracker;
g_return_if_fail (GTK_IS_EVENT_RECOGNIZER (recognizer));
g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
g_return_if_fail (event != NULL);
tracker = g_object_new (GTK_EVENT_RECOGNIZER_GET_CLASS (recognizer)->tracker_type,
"recognizer", recognizer,
"widget", widget,
NULL);
_gtk_event_tracker_add (tracker);
_gtk_event_recognizer_track (recognizer,
tracker,
event);
}
void
_gtk_event_recognizer_recognize (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event)
{
GtkEventRecognizerClass *klass;
g_return_if_fail (GTK_IS_EVENT_RECOGNIZER (recognizer));
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (event != NULL);
klass = GTK_EVENT_RECOGNIZER_GET_CLASS (recognizer);
klass->recognize (recognizer, widget, event);
}
gboolean
_gtk_event_recognizer_track (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
GdkEvent *event)
{
GtkEventRecognizerClass *klass;
g_return_val_if_fail (GTK_IS_EVENT_RECOGNIZER (recognizer), FALSE);
g_return_val_if_fail (GTK_IS_EVENT_TRACKER (tracker), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if (gtk_event_tracker_is_finished (tracker))
return FALSE;
klass = GTK_EVENT_RECOGNIZER_GET_CLASS (recognizer);
return klass->track (recognizer, tracker, event);
}

104
gtk/gtkeventrecognizer.h Normal file
View File

@@ -0,0 +1,104 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_EVENT_RECOGNIZER_H__
#define __GTK_EVENT_RECOGNIZER_H__
#include <gdk/gdk.h>
#include <gtk/gtktypes.h>
G_BEGIN_DECLS
#define GTK_TYPE_EVENT_RECOGNIZER (gtk_event_recognizer_get_type ())
#define GTK_EVENT_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_EVENT_RECOGNIZER, GtkEventRecognizer))
#define GTK_EVENT_RECOGNIZER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_EVENT_RECOGNIZER, GtkEventRecognizerClass))
#define GTK_IS_EVENT_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_EVENT_RECOGNIZER))
#define GTK_IS_EVENT_RECOGNIZER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_EVENT_RECOGNIZER))
#define GTK_EVENT_RECOGNIZER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_EVENT_RECOGNIZER, GtkEventRecognizerClass))
typedef struct _GtkEventRecognizerClass GtkEventRecognizerClass;
typedef struct _GtkEventRecognizerPrivate GtkEventRecognizerPrivate;
typedef struct _GtkEventRecognizerClassPrivate GtkEventRecognizerClassPrivate;
struct _GtkEventRecognizer
{
GObject parent;
GtkEventRecognizerPrivate *priv;
};
struct _GtkEventRecognizerClass
{
GObjectClass parent_class;
/* XXX: Put into private struct */
gint event_mask;
GType tracker_type;
void (* recognize) (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event);
gboolean (* track) (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
GdkEvent *event);
/* signals */
void (* started) (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker);
void (* updated) (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker);
void (* cancelled) (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker);
void (* finished) (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker);
/* Padding for future expansion */
void (*_gtk_reserved0) (void);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_event_recognizer_get_type (void) G_GNUC_CONST;
gint gtk_event_recognizer_class_get_event_mask (GtkEventRecognizerClass *klass);
void gtk_event_recognizer_class_set_event_mask (GtkEventRecognizerClass *klass,
gint event_mask);
GType gtk_event_recognizer_class_get_tracker_type (GtkEventRecognizerClass *klass);
void gtk_event_recognizer_class_set_tracker_type (GtkEventRecognizerClass *klass,
GType tracker_type);
void gtk_event_recognizer_create_tracker (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event);
G_END_DECLS
#endif /* __GTK_EVENT_RECOGNIZER_H__ */

View File

@@ -0,0 +1,35 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_EVENT_RECOGNIZER_PRIVATE_H__
#define __GTK_EVENT_RECOGNIZER_PRIVATE_H__
#include <gdk/gdk.h>
#include <gtk/gtktypes.h>
void _gtk_event_recognizer_recognize (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event);
gboolean _gtk_event_recognizer_track (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
GdkEvent *event);
#endif /* __GTK_EVENT_RECOGNIZER_PRIVATE_H__ */

456
gtk/gtkeventtracker.c Normal file
View File

@@ -0,0 +1,456 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkeventtracker.h"
#include "gtkeventrecognizer.h"
#include "gtkeventrecognizerprivate.h"
#include "gtkintl.h"
#include "gtkwidget.h"
/**
* SECTION:gtkeventtracker
* @Short_description: Tracks the events from a #GtkEventRecognizer
* @Title: GtkEventTracker
* @See_also: #GtkEventRecognizer
*
* The #GtkEventTracker object - or a subclass of it - is used to track
* sequences of events as recognized by a #GtkEventRecognizer. Once the
* recognizer finds it can potentially identify a sequence of events, it
* creates a #GtkEventTracker and uses it to store information about the
* event. See the event handling howto for a highlevel overview.
*
* #GtkEventTracker was added in GTK 3.6.
*/
enum {
PROP_0,
PROP_RECOGNIZER,
PROP_WIDGET
};
struct _GtkEventTrackerPrivate {
GtkEventRecognizer *recognizer;
GtkWidget *widget;
GtkEventTracker *prev;
GtkEventTracker *next;
guint started :1;
guint finished :1;
guint cancelled :1;
};
G_DEFINE_ABSTRACT_TYPE (GtkEventTracker, gtk_event_tracker, G_TYPE_OBJECT)
static GtkEventTracker *first_tracker = NULL;
static GtkEventTracker *last_tracker = NULL;
static void
gtk_event_tracker_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkEventTracker *tracker = GTK_EVENT_TRACKER (object);
GtkEventTrackerPrivate *priv = tracker->priv;
switch (prop_id)
{
case PROP_RECOGNIZER:
priv->recognizer = g_value_dup_object (value);
if (priv->recognizer == NULL)
g_critical ("Attempting to construct a `%s' without a recognizer", G_OBJECT_TYPE_NAME (object));
break;
case PROP_WIDGET:
priv->widget = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_event_tracker_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkEventTracker *tracker = GTK_EVENT_TRACKER (object);
GtkEventTrackerPrivate *priv = tracker->priv;
switch (prop_id)
{
case PROP_RECOGNIZER:
g_value_set_object (value, priv->recognizer);
break;
case PROP_WIDGET:
g_value_set_object (value, priv->widget);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_event_tracker_dispose (GObject *object)
{
GtkEventTracker *tracker = GTK_EVENT_TRACKER (object);
GtkEventTrackerPrivate *priv = tracker->priv;
if (priv->prev)
priv->prev->priv->next = priv->next;
else
first_tracker = priv->next;
if (priv->next)
priv->next->priv->prev = priv->prev;
else
last_tracker = priv->prev;
g_clear_object (&priv->recognizer);
g_clear_object (&priv->widget);
G_OBJECT_CLASS (gtk_event_tracker_parent_class)->dispose (object);
}
static void
gtk_event_tracker_class_init (GtkEventTrackerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_event_tracker_dispose;
object_class->set_property = gtk_event_tracker_set_property;
object_class->get_property = gtk_event_tracker_get_property;
g_object_class_install_property (object_class,
PROP_RECOGNIZER,
g_param_spec_object ("recognizer",
P_("recognizer"),
P_("Recognizer running this tracker"),
GTK_TYPE_EVENT_RECOGNIZER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class,
PROP_WIDGET,
g_param_spec_object ("widget",
P_("widget"),
P_("Widget that spawned this tracker"),
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_type_class_add_private (object_class, sizeof (GtkEventTrackerPrivate));
}
static void
gtk_event_tracker_init (GtkEventTracker *tracker)
{
tracker->priv = G_TYPE_INSTANCE_GET_PRIVATE (tracker,
GTK_TYPE_EVENT_TRACKER,
GtkEventTrackerPrivate);
}
/**
* gtk_event_tracker_get_recognizer:
* @tracker: The event tracker
*
* Gets the recognizer that spawned this @tracker.
*
* Returns: The recognizer that spawned this tracker
*
* @Since: 3.6
**/
GtkEventRecognizer *
gtk_event_tracker_get_recognizer (GtkEventTracker *tracker)
{
g_return_val_if_fail (GTK_IS_EVENT_TRACKER (tracker), NULL);
return tracker->priv->recognizer;
}
/**
* gtk_event_tracker_get_widget:
* @tracker: The event tracker
*
* Gets the widget that is affected by this tracker.
*
* Returns: The widget this tracker runs on or %NULL if none.
*
* @Since: 3.6
**/
GtkWidget *
gtk_event_tracker_get_widget (GtkEventTracker *tracker)
{
g_return_val_if_fail (GTK_IS_EVENT_TRACKER (tracker), NULL);
return tracker->priv->widget;
}
/**
* gtk_event_tracker_is_cancelled:
* @tracker: The event tracker
*
* Queries if the tracker has been cancelled. A #GtkEventTracker
* can be cancelled for various reasons. See gtk_event_tracker_cancel()
* for details.
*
* Returns: %TRUE if the @tracker has been cancelled
**/
gboolean
gtk_event_tracker_is_cancelled (GtkEventTracker *tracker)
{
g_return_val_if_fail (GTK_IS_EVENT_TRACKER (tracker), TRUE);
return tracker->priv->cancelled;
}
/**
* gtk_event_tracker_is_started:
* @tracker: The event tracker
*
* Checks if the event tracker is started. An event tracker is
* considered started after the GtkEventRecognizer::started signal
* has been emitted for it.
*
* Returns: %TRUE if the event tracker is started
**/
gboolean
gtk_event_tracker_is_started (GtkEventTracker *tracker)
{
g_return_val_if_fail (GTK_IS_EVENT_TRACKER (tracker), TRUE);
return tracker->priv->started;
}
/**
* gtk_event_tracker_is_finished:
* @tracker: The event tracker
*
* Checks if the event tracker is finished. An event tracker is
* considered finished when it will not process events or emit
* signals anymore. At that point, the GtkEventRecognizer::finished
* or GtkEventRecognizer::cancelled signal will have been emitted
* for @recognizer.
*
* Returns: %TRUE if the event tracker is finished
**/
gboolean
gtk_event_tracker_is_finished (GtkEventTracker *tracker)
{
g_return_val_if_fail (GTK_IS_EVENT_TRACKER (tracker), TRUE);
return tracker->priv->finished;
}
/**
* gtk_event_tracker_cancel:
* @tracker: The event tracker
*
* Cancels the event tracker if the event tracker is not finished yet.
* If the event tracker was already finished, this function returns
* immediately.
*
* Cancelling an event tracker will cause the
* GtkEventRecognizer::cancelled signal to be emitted and the @tracker
* will not process any new events.
**/
void
gtk_event_tracker_cancel (GtkEventTracker *tracker)
{
GtkEventTrackerPrivate *priv;
g_return_if_fail (GTK_IS_EVENT_TRACKER (tracker));
priv = tracker->priv;
if (priv->finished)
return;
priv->finished = TRUE;
priv->cancelled = TRUE;
if (priv->started)
g_signal_emit_by_name (priv->recognizer,
"cancelled",
tracker);
else
priv->started = TRUE;
/* release the reference from adding the tracker upon construction */
g_object_unref (tracker);
}
/**
* gtk_event_tracker_start:
* @tracker: The tracker to start
*
* Emits the GtkEventRecognizer::started signal for the @tracker. This
* signal should be emitted when @tracker should be made public and
* widgets using it might want to provide feedback for an impending event
* recognition.
*
* This function should only be called by #GtkEventRecognizer
* implementations.
**/
void
gtk_event_tracker_start (GtkEventTracker *tracker)
{
GtkEventTrackerPrivate *priv;
g_return_if_fail (GTK_IS_EVENT_TRACKER (tracker));
priv = tracker->priv;
if (priv->started)
return;
priv->started = TRUE;
g_signal_emit_by_name (priv->recognizer,
"started",
tracker);
}
/**
* gtk_event_tracker_update:
* @tracker: The tracker to update
*
* Emits the GtkEventRecognizer::updated signal for the @tracker. This
* signal should be emitted when @tracker has updated its state and
* widgets might want to update their state based on it.
*
* This function should only be called by #GtkEventRecognizer
* implementations.
**/
void
gtk_event_tracker_update (GtkEventTracker *tracker)
{
GtkEventTrackerPrivate *priv;
g_return_if_fail (GTK_IS_EVENT_TRACKER (tracker));
priv = tracker->priv;
g_object_ref (tracker);
gtk_event_tracker_start (tracker);
if (priv->finished)
return;
g_signal_emit_by_name (priv->recognizer,
"updated",
tracker);
g_object_unref (tracker);
}
/**
* gtk_event_tracker_finish:
* @tracker: The event tracker
*
* Marks the event tracker as finished and emits the
* GtkEventRecognizer::finished signal. If the @tracker has
* already been finished, nothing happens.
*
* This function should only be called by #GtkEventRecognizer
* implementations.
**/
void
gtk_event_tracker_finish (GtkEventTracker *tracker)
{
GtkEventTrackerPrivate *priv;
g_return_if_fail (GTK_IS_EVENT_TRACKER (tracker));
priv = tracker->priv;
if (priv->finished)
return;
priv->finished = TRUE;
if (priv->started)
g_signal_emit_by_name (priv->recognizer,
"finished",
tracker);
/* release the reference from adding the tracker upon construction */
g_object_unref (tracker);
}
void
_gtk_event_tracker_add (GtkEventTracker *tracker)
{
GtkEventTrackerPrivate *priv = tracker->priv;
g_assert (priv->prev == NULL);
g_assert (priv->next == NULL);
priv->prev = last_tracker;
if (priv->prev)
priv->prev->priv->next = tracker;
else
first_tracker = tracker;
last_tracker = tracker;
}
gboolean
_gtk_event_trackers_invoke (GdkEvent *event)
{
GtkEventTracker *tracker, *next;
gboolean eat_event = FALSE;
g_return_val_if_fail (event != NULL, FALSE);
for (tracker = first_tracker; tracker; tracker = next)
{
g_object_ref (tracker);
eat_event |= _gtk_event_recognizer_track (tracker->priv->recognizer,
tracker,
event);
next = tracker->priv->next;
g_object_unref (tracker);
}
return eat_event;
}
GtkEventTracker *
_gtk_event_tracker_get_first (void)
{
return first_tracker;
}
GtkEventTracker *
_gtk_event_tracker_get_next (GtkEventTracker *tracker)
{
g_return_val_if_fail (GTK_IS_EVENT_TRACKER (tracker), NULL);
return tracker->priv->next;
}

81
gtk/gtkeventtracker.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_EVENT_TRACKER_H__
#define __GTK_EVENT_TRACKER_H__
#include <gtk/gtktypes.h>
G_BEGIN_DECLS
#define GTK_TYPE_EVENT_TRACKER (gtk_event_tracker_get_type ())
#define GTK_EVENT_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_EVENT_TRACKER, GtkEventTracker))
#define GTK_EVENT_TRACKER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_EVENT_TRACKER, GtkEventTrackerClass))
#define GTK_IS_EVENT_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_EVENT_TRACKER))
#define GTK_IS_EVENT_TRACKER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_EVENT_TRACKER))
#define GTK_EVENT_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_EVENT_TRACKER, GtkEventTrackerClass))
typedef struct _GtkEventTrackerClass GtkEventTrackerClass;
typedef struct _GtkEventTrackerPrivate GtkEventTrackerPrivate;
struct _GtkEventTracker
{
GObject parent;
GtkEventTrackerPrivate *priv;
};
struct _GtkEventTrackerClass
{
GObjectClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved0) (void);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_event_tracker_get_type (void) G_GNUC_CONST;
GtkEventRecognizer * gtk_event_tracker_get_recognizer (GtkEventTracker *tracker);
GtkWidget * gtk_event_tracker_get_widget (GtkEventTracker *tracker);
gboolean gtk_event_tracker_is_started (GtkEventTracker *tracker);
gboolean gtk_event_tracker_is_finished (GtkEventTracker *tracker);
gboolean gtk_event_tracker_is_cancelled (GtkEventTracker *tracker);
void gtk_event_tracker_cancel (GtkEventTracker *tracker);
void gtk_event_tracker_start (GtkEventTracker *tracker);
void gtk_event_tracker_update (GtkEventTracker *tracker);
void gtk_event_tracker_finish (GtkEventTracker *tracker);
G_END_DECLS
#endif /* __GTK_EVENT_TRACKER_H__ */

View File

@@ -0,0 +1,36 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_EVENT_TRACKER_PRIVATE_H__
#define __GTK_EVENT_TRACKER_PRIVATE_H__
#include <gdk/gdk.h>
#include <gtk/gtktypes.h>
void _gtk_event_tracker_add (GtkEventTracker *tracker);
gboolean _gtk_event_trackers_invoke (GdkEvent *event);
GtkEventTracker * _gtk_event_tracker_get_first (void);
GtkEventTracker * _gtk_event_tracker_get_next (GtkEventTracker *tracker);
#endif /* __GTK_EVENT_TRACKER_PRIVATE_H__ */

371
gtk/gtkgesture.c Normal file
View File

@@ -0,0 +1,371 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkgesture.h"
#include "gtkeventtrackerprivate.h"
#include "gtkintl.h"
#include "gtksequence.h"
/**
* SECTION:gtkgesture
* @Short_description: Gesture recognition
* @Title: GtkGesture
* @See_also: #GtkGestureRecognizer, #GtkEventTracker
*
* The #GtkGesture object - or rather its subclasses - are #GtkEventTrackers
* that cooperates with other #GtkGestures on the recognizing of
* #GdkSequences.
*
* #GtkGesture was added in GTK 3.6.
*/
enum {
PROP_0
};
struct _GtkGesturePrivate {
GPtrArray *sequences;
guint accepted :1;
};
G_DEFINE_ABSTRACT_TYPE (GtkGesture, gtk_gesture, GTK_TYPE_EVENT_TRACKER)
static void
gtk_gesture_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
//GtkGesture *gesture = GTK_GESTURE (object);
//GtkGesturePrivate *priv = gesture->priv;
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_gesture_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
//GtkGesture *gesture = GTK_GESTURE (object);
//GtkGesturePrivate *priv = gesture->priv;
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_gesture_remove_all_sequences (GtkGesture *gesture)
{
GtkGesturePrivate *priv = gesture->priv;
if (priv->accepted)
return;
while (priv->sequences->len > 0)
gtk_gesture_remove_sequence (gesture, g_ptr_array_index (priv->sequences,
priv->sequences->len - 1));
}
static void
gtk_gesture_dispose (GObject *object)
{
GtkGesture *gesture = GTK_GESTURE (object);
GtkGesturePrivate *priv = gesture->priv;
gtk_gesture_remove_all_sequences (gesture);
g_ptr_array_unref (priv->sequences);
priv->sequences = NULL;
G_OBJECT_CLASS (gtk_gesture_parent_class)->dispose (object);
}
static void
gtk_gesture_default_sequence_given (GtkGesture *gesture,
GdkEventSequence *sequence)
{
}
static void
gtk_gesture_default_sequence_stolen (GtkGesture *gesture,
GdkEventSequence *sequence,
GtkGesture *stealer)
{
gtk_event_tracker_cancel (GTK_EVENT_TRACKER (gesture));
}
static void
gtk_gesture_class_init (GtkGestureClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
klass->sequence_stolen = gtk_gesture_default_sequence_stolen;
klass->sequence_given = gtk_gesture_default_sequence_given;
object_class->dispose = gtk_gesture_dispose;
object_class->set_property = gtk_gesture_set_property;
object_class->get_property = gtk_gesture_get_property;
g_type_class_add_private (object_class, sizeof (GtkGesturePrivate));
}
static void
gtk_gesture_init (GtkGesture *gesture)
{
GtkGesturePrivate *priv;
priv = gesture->priv = G_TYPE_INSTANCE_GET_PRIVATE (gesture,
GTK_TYPE_GESTURE,
GtkGesturePrivate);
priv->sequences = g_ptr_array_new ();
}
static void
gtk_gesture_accept_sequence (GtkGesture *stealer,
GdkEventSequence *sequence)
{
GtkEventTracker *tracker, *next;
for (tracker = _gtk_event_tracker_get_next (GTK_EVENT_TRACKER (stealer));
tracker;
tracker = next)
{
GtkGesture *gesture;
next = _gtk_event_tracker_get_next (tracker);
if (!GTK_IS_GESTURE (tracker))
continue;
gesture = GTK_GESTURE (tracker);
if (!gtk_gesture_has_sequence (gesture, sequence))
continue;
/* need some magic here because a lot of gestures wanna cancel themselves
* in this vfunc */
g_object_ref (gesture);
GTK_GESTURE_GET_CLASS (gesture)->sequence_stolen (gesture,
sequence,
stealer);
next = _gtk_event_tracker_get_next (tracker);
g_object_unref (gesture);
}
}
static void
gtk_gesture_give_sequence (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGestureClass *klass = GTK_GESTURE_GET_CLASS (gesture);
klass->sequence_given (gesture, sequence);
}
/**
* gtk_gesture_add_sequence:
* @gesture: the gesture
* @sequence: the sequence to add to @gesture
*
* Marks @gesture as working with @sequence. If @gesture is or gets
* accepted, other gestures will be notified about @gesture using @sequence
* and @gesture will be notified if other gestures use @sequence.
**/
void
gtk_gesture_add_sequence (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGesturePrivate *priv;
gboolean new_owner;
g_return_if_fail (GTK_IS_GESTURE (gesture));
g_return_if_fail (sequence != NULL);
priv = gesture->priv;
new_owner = gtk_sequence_get_owner (sequence) == NULL;
g_ptr_array_add (priv->sequences, sequence);
if (new_owner)
gtk_gesture_give_sequence (gesture, sequence);
if (priv->accepted)
gtk_gesture_accept_sequence (gesture, sequence);
}
/**
* gtk_gesture_remove_sequence:
* @gesture: the gesture
* @sequence: the sequence to remove. It must have been added with
* gtk_gesture_add_sequence() previously.
*
* Removes the sequence from the list of tracked sequences. This function
* does nothing if the gesture has been accepted.
*
* This function should only be called from #GtkGesture implementations.
**/
void
gtk_gesture_remove_sequence (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGesturePrivate *priv;
gboolean was_owner;
g_return_if_fail (GTK_IS_GESTURE (gesture));
g_return_if_fail (sequence != NULL);
priv = gesture->priv;
if (priv->accepted)
return;
was_owner = gtk_gesture_owns_sequence (gesture, sequence);
g_ptr_array_remove (priv->sequences, sequence);
if (was_owner)
{
GtkEventTracker *tracker;
for (tracker = _gtk_event_tracker_get_next (GTK_EVENT_TRACKER (gesture));
tracker;
tracker = _gtk_event_tracker_get_next (tracker))
{
if (GTK_IS_GESTURE (tracker) &&
gtk_gesture_has_sequence (GTK_GESTURE (tracker), sequence))
{
gtk_gesture_give_sequence (GTK_GESTURE (tracker), sequence);
break;
}
}
}
}
gboolean
gtk_gesture_has_sequence (GtkGesture *gesture,
GdkEventSequence *sequence)
{
GtkGesturePrivate *priv;
guint i;
g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
g_return_val_if_fail (sequence != NULL, FALSE);
priv = gesture->priv;
for (i = 0; i < priv->sequences->len; i++)
{
if (g_ptr_array_index (priv->sequences, i) == sequence)
return TRUE;
}
return FALSE;
}
gboolean
gtk_gesture_owns_sequence (GtkGesture *gesture,
GdkEventSequence *sequence)
{
g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
g_return_val_if_fail (sequence != NULL, FALSE);
return gtk_sequence_get_owner (sequence) == gesture;
}
gboolean
gtk_gesture_owns_all_sequences (GtkGesture *gesture)
{
GtkGesturePrivate *priv;
guint i;
g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
priv = gesture->priv;
for (i = 0; i < priv->sequences->len; i++)
{
if (!gtk_gesture_owns_sequence (gesture,
g_ptr_array_index (priv->sequences, i)))
return FALSE;
}
return TRUE;
}
/**
* gtk_gesture_accept:
* @gesture: the gesture to accept
*
* Accepts @gesture if it hasn't been accepted yet. An accepted gesture
* is a gesture that will successfully finish to recognize itself.
*
* If a gesture marks itself as accepted, all its sequences that were
* added with gtk_gesture_add_sequence() are assumed to be consumed by
* this @gesture and other gestures will be notified about this.
*
* This function should only be called from #GtkGesture implementations.
**/
void
gtk_gesture_accept (GtkGesture *gesture)
{
GtkGesturePrivate *priv;
guint i;
g_return_if_fail (GTK_IS_GESTURE (gesture));
priv = gesture->priv;
if (priv->accepted)
return;
priv->accepted = TRUE;
for (i = 0; i < priv->sequences->len; i++)
{
gtk_gesture_accept_sequence (gesture,
g_ptr_array_index (priv->sequences, i));
}
}
gboolean
gtk_gesture_is_accepted (GtkGesture *gesture)
{
g_return_val_if_fail (GTK_IS_GESTURE (gesture), FALSE);
return gesture->priv->accepted;
}

89
gtk/gtkgesture.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_GESTURE_H__
#define __GTK_GESTURE_H__
#include <gtk/gtkeventtracker.h>
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE (gtk_gesture_get_type ())
#define GTK_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_GESTURE, GtkGesture))
#define GTK_GESTURE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_GESTURE, GtkGestureClass))
#define GTK_IS_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_GESTURE))
#define GTK_IS_GESTURE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_GESTURE))
#define GTK_GESTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GESTURE, GtkGestureClass))
typedef struct _GtkGesture GtkGesture;
typedef struct _GtkGestureClass GtkGestureClass;
typedef struct _GtkGesturePrivate GtkGesturePrivate;
struct _GtkGesture
{
GtkEventTracker parent;
GtkGesturePrivate *priv;
};
struct _GtkGestureClass
{
GtkEventTrackerClass parent_class;
void (* sequence_given) (GtkGesture * gesture,
GdkEventSequence * sequence);
void (* sequence_stolen) (GtkGesture * gesture,
GdkEventSequence * sequence,
GtkGesture * accepter);
/* Padding for future expansion */
void (*_gtk_reserved0) (void);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_gesture_get_type (void) G_GNUC_CONST;
void gtk_gesture_add_sequence (GtkGesture *gesture,
GdkEventSequence *sequence);
void gtk_gesture_remove_sequence (GtkGesture *gesture,
GdkEventSequence *sequence);
gboolean gtk_gesture_has_sequence (GtkGesture *gesture,
GdkEventSequence *sequence);
gboolean gtk_gesture_owns_sequence (GtkGesture *gesture,
GdkEventSequence *sequence);
gboolean gtk_gesture_owns_all_sequences(GtkGesture *gesture);
void gtk_gesture_accept (GtkGesture *gesture);
gboolean gtk_gesture_is_accepted (GtkGesture *gesture);
G_END_DECLS
#endif /* __GTK_GESTURE_H__ */

View File

@@ -0,0 +1,60 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkgesturerecognizer.h"
#include "gtkgesture.h"
/**
* SECTION:gtkgesturerecognizer
* @Short_description: Recognizes gestures
* @Title: GtkGestureRecognizer
* @See_also: #GtkGesture, #GtkEventRecognizer
*
* FIXME
*
* #GtkGestureRecognizer was added in GTK 3.6.
*/
G_DEFINE_ABSTRACT_TYPE (GtkGestureRecognizer, gtk_gesture_recognizer, GTK_TYPE_EVENT_RECOGNIZER)
static void
gtk_gesture_recognizer_finished (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker)
{
gtk_gesture_accept (GTK_GESTURE (tracker));
}
static void
gtk_gesture_recognizer_class_init (GtkGestureRecognizerClass *klass)
{
GtkEventRecognizerClass *recognizer_class = GTK_EVENT_RECOGNIZER_CLASS (klass);
recognizer_class->finished = gtk_gesture_recognizer_finished;
gtk_event_recognizer_class_set_tracker_type (recognizer_class, GTK_TYPE_GESTURE);
}
static void
gtk_gesture_recognizer_init (GtkGestureRecognizer *recognizer)
{
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_GESTURE_RECOGNIZER_H__
#define __GTK_GESTURE_RECOGNIZER_H__
#include <gtk/gtkeventrecognizer.h>
G_BEGIN_DECLS
#define GTK_TYPE_GESTURE_RECOGNIZER (gtk_gesture_recognizer_get_type ())
#define GTK_GESTURE_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_GESTURE_RECOGNIZER, GtkGestureRecognizer))
#define GTK_GESTURE_RECOGNIZER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_GESTURE_RECOGNIZER, GtkGestureRecognizerClass))
#define GTK_IS_GESTURE_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_GESTURE_RECOGNIZER))
#define GTK_IS_GESTURE_RECOGNIZER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_GESTURE_RECOGNIZER))
#define GTK_GESTURE_RECOGNIZER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GESTURE_RECOGNIZER, GtkGestureRecognizerClass))
typedef struct _GtkGestureRecognizer GtkGestureRecognizer;
typedef struct _GtkGestureRecognizerClass GtkGestureRecognizerClass;
typedef struct _GtkGestureRecognizerPrivate GtkGestureRecognizerPrivate;
struct _GtkGestureRecognizer
{
GtkEventRecognizer parent;
GtkGestureRecognizerPrivate *priv;
};
struct _GtkGestureRecognizerClass
{
GtkEventRecognizerClass parent_class;
};
GType gtk_gesture_recognizer_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __GTK_GESTURE_RECOGNIZER_H__ */

View File

@@ -114,6 +114,7 @@
#include "gtkclipboard.h"
#include "gtkdebug.h"
#include "gtkdnd.h"
#include "gtkeventtrackerprivate.h"
#include "gtkmain.h"
#include "gtkmenu.h"
#include "gtkmodules.h"
@@ -1647,6 +1648,9 @@ gtk_main_do_event (GdkEvent *event)
case GDK_WINDOW_STATE:
case GDK_GRAB_BROKEN:
case GDK_DAMAGE:
if (_gtk_event_trackers_invoke (event))
break;
if (!_gtk_widget_captured_event (event_widget, event))
gtk_widget_event (event_widget, event);
break;
@@ -1656,6 +1660,9 @@ gtk_main_do_event (GdkEvent *event)
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
case GDK_TOUCH_BEGIN:
if (_gtk_event_trackers_invoke (event))
break;
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
gtk_propagate_event (grab_widget, event);
break;
@@ -1709,11 +1716,17 @@ gtk_main_do_event (GdkEvent *event)
case GDK_TOUCH_UPDATE:
case GDK_TOUCH_END:
case GDK_TOUCH_CANCEL:
if (_gtk_event_trackers_invoke (event))
break;
if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
gtk_propagate_event (grab_widget, event);
break;
case GDK_ENTER_NOTIFY:
if (_gtk_event_trackers_invoke (event))
break;
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
_gtk_widget_set_device_window (event_widget,
@@ -1725,6 +1738,9 @@ gtk_main_do_event (GdkEvent *event)
break;
case GDK_LEAVE_NOTIFY:
if (_gtk_event_trackers_invoke (event))
break;
if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
_gtk_widget_set_device_window (event_widget,

312
gtk/gtkpinchpangesture.c Normal file
View File

@@ -0,0 +1,312 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkpinchpangesture.h"
#include "gtksequencetrackerprivate.h"
#include "gtkpinchpanrecognizer.h"
#include <math.h>
/**
* SECTION:gtkpinchpangesture
* @Short_description: Gesture for pinch, pan and rotation
* @Title: GtkPinchPanGesture
* @See_also: #GtkPinchPanRecognizer
*
* The #GtkPinchPanGesture object is used to to track pinch, pan and rotation
* gestures. These are usually used to implement scrolling, zooming and rotation
* respectively on scrollable widgets.
*
* #GtkPinchPanGesture was added in GTK 3.6.
*/
enum {
PROP_0,
};
struct _GtkPinchPanGesturePrivate {
GtkSequenceTracker *sequence[2];
double initial_distance;
double initial_angle;
};
G_DEFINE_TYPE (GtkPinchPanGesture, gtk_pinch_pan_gesture, GTK_TYPE_GESTURE)
static void
gtk_pinch_pan_gesture_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
//GtkPinchPanGesture *gesture = GTK_PINCH_PAN_GESTURE (object);
//GtkPinchPanGesturePrivate *priv = gesture->priv;
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_pinch_pan_gesture_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
//GtkPinchPanGesture *gesture = GTK_PINCH_PAN_GESTURE (object);
//GtkPinchPanGesturePrivate *priv = gesture->priv;
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_pinch_pan_gesture_dispose (GObject *object)
{
//GtkPinchPanGesture *gesture = GTK_PINCH_PAN_GESTURE (object);
G_OBJECT_CLASS (gtk_pinch_pan_gesture_parent_class)->dispose (object);
}
static void
gtk_pinch_pan_gesture_class_init (GtkPinchPanGestureClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_pinch_pan_gesture_dispose;
object_class->set_property = gtk_pinch_pan_gesture_set_property;
object_class->get_property = gtk_pinch_pan_gesture_get_property;
g_type_class_add_private (object_class, sizeof (GtkPinchPanGesturePrivate));
}
static void
gtk_pinch_pan_gesture_init (GtkPinchPanGesture *gesture)
{
gesture->priv = G_TYPE_INSTANCE_GET_PRIVATE (gesture,
GTK_TYPE_PINCH_PAN_GESTURE,
GtkPinchPanGesturePrivate);
}
gboolean
_gtk_pinch_pan_gesture_begin (GtkPinchPanGesture *gesture,
GdkEvent *event)
{
GtkPinchPanGesturePrivate *priv = gesture->priv;
if (priv->sequence[1] != NULL)
return FALSE;
if (priv->sequence[0] == NULL)
{
priv->sequence[0] = _gtk_sequence_tracker_new (event);
gtk_gesture_add_sequence (GTK_GESTURE (gesture), event->touch.sequence);
}
else
{
priv->sequence[1] = _gtk_sequence_tracker_new (event);
gtk_gesture_add_sequence (GTK_GESTURE (gesture), event->touch.sequence);
}
if (priv->sequence[1])
{
double x, y;
_gtk_sequence_tracker_compute_distance (priv->sequence[0],
priv->sequence[1],
&x, &y);
priv->initial_distance = sqrt (x * x + y * y);
priv->initial_angle = atan2 (y, x);
gtk_event_tracker_start (GTK_EVENT_TRACKER (gesture));
}
return FALSE;
}
gboolean
gtk_pinch_pan_gesture_update_for_event (GtkPinchPanGesture *gesture,
GdkEvent *event)
{
GtkPinchPanGesturePrivate *priv = gesture->priv;
gboolean result = FALSE;
guint i;
for (i = 0; i < 2; i++)
{
if (priv->sequence[i])
result |= _gtk_sequence_tracker_update (priv->sequence[i], event);
}
return result;
}
gboolean
_gtk_pinch_pan_gesture_update (GtkPinchPanGesture *gesture,
GdkEvent *event)
{
if (gtk_pinch_pan_gesture_update_for_event (gesture, event) &&
gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)))
gtk_event_tracker_update (GTK_EVENT_TRACKER (gesture));
return FALSE;
}
gboolean
_gtk_pinch_pan_gesture_end (GtkPinchPanGesture *gesture,
GdkEvent *event)
{
if (gtk_pinch_pan_gesture_update_for_event (gesture, event))
{
if (gesture->priv->sequence[1])
gtk_event_tracker_finish (GTK_EVENT_TRACKER (gesture));
else
gtk_event_tracker_cancel (GTK_EVENT_TRACKER (gesture));
}
return FALSE;
}
gboolean
_gtk_pinch_pan_gesture_cancel (GtkPinchPanGesture *gesture,
GdkEvent *event)
{
if (gtk_pinch_pan_gesture_update_for_event (gesture, event))
gtk_event_tracker_cancel (GTK_EVENT_TRACKER (gesture));
return FALSE;
}
void
gtk_pinch_pan_gesture_get_offset (GtkPinchPanGesture *gesture,
double *x,
double *y)
{
GtkPinchPanGesturePrivate *priv;
g_return_if_fail (GTK_IS_PINCH_PAN_GESTURE (gesture));
priv = gesture->priv;
if (!gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)) ||
gtk_event_tracker_is_cancelled (GTK_EVENT_TRACKER (gesture)))
{
if (x)
*x = 0;
if (y)
*y = 0;
return;
}
if (x)
*x = (_gtk_sequence_tracker_get_x_offset (priv->sequence[0])
+ _gtk_sequence_tracker_get_x_offset (priv->sequence[1])) / 2;
if (y)
*y = (_gtk_sequence_tracker_get_y_offset (priv->sequence[0])
+ _gtk_sequence_tracker_get_y_offset (priv->sequence[1])) / 2;
}
double
gtk_pinch_pan_gesture_get_x_offset (GtkPinchPanGesture *gesture)
{
GtkPinchPanGesturePrivate *priv;
g_return_val_if_fail (GTK_IS_PINCH_PAN_GESTURE (gesture), 0.0);
priv = gesture->priv;
if (!gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)) ||
gtk_event_tracker_is_cancelled (GTK_EVENT_TRACKER (gesture)))
return 0;
return (_gtk_sequence_tracker_get_x_offset (priv->sequence[0])
+ _gtk_sequence_tracker_get_x_offset (priv->sequence[1])) / 2;
}
double
gtk_pinch_pan_gesture_get_y_offset (GtkPinchPanGesture *gesture)
{
GtkPinchPanGesturePrivate *priv;
g_return_val_if_fail (GTK_IS_PINCH_PAN_GESTURE (gesture), 0.0);
priv = gesture->priv;
if (!gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)) ||
gtk_event_tracker_is_cancelled (GTK_EVENT_TRACKER (gesture)))
return 0;
return (_gtk_sequence_tracker_get_y_offset (priv->sequence[0])
+ _gtk_sequence_tracker_get_y_offset (priv->sequence[1])) / 2;
}
double
gtk_pinch_pan_gesture_get_rotation (GtkPinchPanGesture *gesture)
{
GtkPinchPanGesturePrivate *priv;
double x, y, angle;
g_return_val_if_fail (GTK_IS_PINCH_PAN_GESTURE (gesture), 0.0);
priv = gesture->priv;
if (!gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)) ||
gtk_event_tracker_is_cancelled (GTK_EVENT_TRACKER (gesture)))
return 0;
_gtk_sequence_tracker_compute_distance (priv->sequence[0],
priv->sequence[1],
&x, &y);
angle = atan2 (y, x);
angle -= priv->initial_angle;
angle *= 180 / G_PI;
angle = fmod (angle + 360, 360);
return angle;
}
double
gtk_pinch_pan_gesture_get_zoom (GtkPinchPanGesture *gesture)
{
GtkPinchPanGesturePrivate *priv;
double x, y;
g_return_val_if_fail (GTK_IS_PINCH_PAN_GESTURE (gesture), 1.0);
priv = gesture->priv;
if (!gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)) ||
gtk_event_tracker_is_cancelled (GTK_EVENT_TRACKER (gesture)))
return 1;
_gtk_sequence_tracker_compute_distance (priv->sequence[0],
priv->sequence[1],
&x, &y);
return sqrt (x * x + y * y) / priv->initial_distance;
}

85
gtk/gtkpinchpangesture.h Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_PINCH_PAN_GESTURE_H__
#define __GTK_PINCH_PAN_GESTURE_H__
#include <gtk/gtkgesture.h>
G_BEGIN_DECLS
#define GTK_TYPE_PINCH_PAN_GESTURE (gtk_pinch_pan_gesture_get_type ())
#define GTK_PINCH_PAN_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_PINCH_PAN_GESTURE, GtkPinchPanGesture))
#define GTK_PINCH_PAN_GESTURE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_PINCH_PAN_GESTURE, GtkPinchPanGestureClass))
#define GTK_IS_PINCH_PAN_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_PINCH_PAN_GESTURE))
#define GTK_IS_PINCH_PAN_GESTURE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_PINCH_PAN_GESTURE))
#define GTK_PINCH_PAN_GESTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PINCH_PAN_GESTURE, GtkPinchPanGestureClass))
typedef struct _GtkPinchPanGesture GtkPinchPanGesture;
typedef struct _GtkPinchPanGestureClass GtkPinchPanGestureClass;
typedef struct _GtkPinchPanGesturePrivate GtkPinchPanGesturePrivate;
struct _GtkPinchPanGesture
{
GtkGesture parent;
GtkPinchPanGesturePrivate *priv;
};
struct _GtkPinchPanGestureClass
{
GtkGestureClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved0) (void);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_pinch_pan_gesture_get_type (void) G_GNUC_CONST;
double gtk_pinch_pan_gesture_get_rotation (GtkPinchPanGesture *gesture);
double gtk_pinch_pan_gesture_get_zoom (GtkPinchPanGesture *gesture);
double gtk_pinch_pan_gesture_get_x_offset (GtkPinchPanGesture *gesture);
double gtk_pinch_pan_gesture_get_y_offset (GtkPinchPanGesture *gesture);
#include <gdk/gdk.h>
gboolean _gtk_pinch_pan_gesture_begin (GtkPinchPanGesture *gesture,
GdkEvent *event);
gboolean _gtk_pinch_pan_gesture_update (GtkPinchPanGesture *gesture,
GdkEvent *event);
gboolean _gtk_pinch_pan_gesture_end (GtkPinchPanGesture *gesture,
GdkEvent *event);
gboolean _gtk_pinch_pan_gesture_cancel (GtkPinchPanGesture *gesture,
GdkEvent *event);
G_END_DECLS
#endif /* __GTK_PINCH_PAN_GESTURE_H__ */

View File

@@ -0,0 +1,95 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkpinchpanrecognizer.h"
#include "gtkpinchpangesture.h"
/**
* SECTION:gtkpinch_panrecognizer
* @Short_description: Recognizes vertical and horizontal pinch_pan gestures
* @Title: GtkPinchPanRecognizer
* @See_also: #GtkPinchPanGesture
*
* #GtkPinchPanRecoginzer recognizes vertical and horizontal pinch_pan gestures.
*
* #GtkPinchPanRecognizer was added in GTK 3.6.
*/
G_DEFINE_TYPE (GtkPinchPanRecognizer, gtk_pinch_pan_recognizer, GTK_TYPE_GESTURE_RECOGNIZER)
static void
gtk_pinch_pan_recognizer_recognize (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event)
{
if (event->type == GDK_TOUCH_BEGIN)
gtk_event_recognizer_create_tracker (recognizer, widget, event);
}
static gboolean
gtk_pinch_pan_recognizer_track (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
GdkEvent *event)
{
GtkPinchPanGesture *gesture = GTK_PINCH_PAN_GESTURE (tracker);
switch (event->type)
{
case GDK_TOUCH_BEGIN:
return _gtk_pinch_pan_gesture_begin (gesture, event);
case GDK_TOUCH_END:
return _gtk_pinch_pan_gesture_end (gesture, event);
case GDK_TOUCH_UPDATE:
return _gtk_pinch_pan_gesture_update (gesture, event);
case GDK_TOUCH_CANCEL:
return _gtk_pinch_pan_gesture_cancel (gesture, event);
default:
return FALSE;
}
}
static void
gtk_pinch_pan_recognizer_class_init (GtkPinchPanRecognizerClass *klass)
{
GtkEventRecognizerClass *recognizer_class = GTK_EVENT_RECOGNIZER_CLASS (klass);
recognizer_class->recognize = gtk_pinch_pan_recognizer_recognize;
recognizer_class->track = gtk_pinch_pan_recognizer_track;
gtk_event_recognizer_class_set_event_mask (recognizer_class,
GDK_TOUCH_MASK);
gtk_event_recognizer_class_set_tracker_type (recognizer_class,
GTK_TYPE_PINCH_PAN_GESTURE);
}
static void
gtk_pinch_pan_recognizer_init (GtkPinchPanRecognizer *recognizer)
{
}
GtkEventRecognizer *
gtk_pinch_pan_recognizer_new (void)
{
return g_object_new (GTK_TYPE_PINCH_PAN_RECOGNIZER, NULL);
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_PINCH_PAN_RECOGNIZER_H__
#define __GTK_PINCH_PAN_RECOGNIZER_H__
#include <gtk/gtkgesturerecognizer.h>
G_BEGIN_DECLS
#define GTK_TYPE_PINCH_PAN_RECOGNIZER (gtk_pinch_pan_recognizer_get_type ())
#define GTK_PINCH_PAN_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_PINCH_PAN_RECOGNIZER, GtkPinchPanRecognizer))
#define GTK_PINCH_PAN_RECOGNIZER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_PINCH_PAN_RECOGNIZER, GtkPinchPanRecognizerClass))
#define GTK_IS_PINCH_PAN_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_PINCH_PAN_RECOGNIZER))
#define GTK_IS_PINCH_PAN_RECOGNIZER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_PINCH_PAN_RECOGNIZER))
#define GTK_PINCH_PAN_RECOGNIZER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PINCH_PAN_RECOGNIZER, GtkPinchPanRecognizerClass))
typedef struct _GtkPinchPanRecognizer GtkPinchPanRecognizer;
typedef struct _GtkPinchPanRecognizerClass GtkPinchPanRecognizerClass;
typedef struct _GtkPinchPanRecognizerPrivate GtkPinchPanRecognizerPrivate;
struct _GtkPinchPanRecognizer
{
GtkGestureRecognizer parent;
GtkPinchPanRecognizerPrivate *priv;
};
struct _GtkPinchPanRecognizerClass
{
GtkGestureRecognizerClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved0) (void);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_pinch_pan_recognizer_get_type (void) G_GNUC_CONST;
GtkEventRecognizer * gtk_pinch_pan_recognizer_new (void);
G_END_DECLS
#endif /* __GTK_PINCH_PAN_RECOGNIZER_H__ */

277
gtk/gtksequencetracker.c Normal file
View File

@@ -0,0 +1,277 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Benjamin Otte <otte@gnome.org>
*
* 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/>.
*/
#include "config.h"
#include "gtksequencetrackerprivate.h"
#include <math.h>
#define GTK_SEQUENCE_TRACKER_HISTORY_SIZE 8
typedef struct _GtkSequenceTrackerClass GtkSequenceTrackerClass;
struct _GtkSequenceTrackerClass {
gboolean (* update) (GtkSequenceTracker *tracker,
GdkEvent *event,
double *x,
double *y);
};
struct _GtkSequenceTracker {
GtkSequenceTrackerClass *klass;
struct {
guint time;
GtkMovementDirection dir;
double x; /* x position in pixels - will be compared to start_x */
double y; /* y position in pixels - will be compared to start_y */
} history[GTK_SEQUENCE_TRACKER_HISTORY_SIZE];
guint history_index; /* current item */
GdkEventSequence *sequence; /* sequence we're tracking */
double start_x; /* NOT screen location, but in device coordinates */
double start_y; /* NOT screen location, but in device coordinates */
};
/* MOUSE */
/* FIXME */
/* TOUCHSCREEN */
/* FIXME */
/* TOUCHPAD */
static gboolean
gtk_sequence_tracker_touchpad_update (GtkSequenceTracker *tracker,
GdkEvent *event,
double *x,
double *y)
{
GdkDevice *device = gdk_event_get_device (event);
switch (event->type)
{
case GDK_TOUCH_BEGIN:
tracker->sequence = gdk_event_get_event_sequence (event);
/* fall through */
case GDK_TOUCH_UPDATE:
case GDK_TOUCH_END:
if (tracker->sequence != gdk_event_get_event_sequence (event))
return FALSE;
if (gdk_device_get_axis (device,
event->touch.axes,
GDK_AXIS_X_RELATIVE,
x))
{
*x *= gdk_screen_get_width (gdk_display_get_default_screen (gdk_device_get_display (device)));
}
else
{
g_warning ("Could not query X value");
*x = 0;
}
if (gdk_device_get_axis (device,
event->touch.axes,
GDK_AXIS_Y_RELATIVE,
y))
{
*y *= gdk_screen_get_height (gdk_display_get_default_screen (gdk_device_get_display (device)));
}
else
{
g_warning ("Could not query Y value");
*y = 0;
}
return TRUE;
default:
return FALSE;
}
}
GtkSequenceTrackerClass GTK_SEQUENCE_TRACKER_CLASS_TOUCHPAD = {
gtk_sequence_tracker_touchpad_update
};
/* API */
GtkSequenceTracker *
_gtk_sequence_tracker_new (GdkEvent *event)
{
GtkSequenceTrackerClass *klass;
GtkSequenceTracker *tracker;
guint i, time;
switch (event->type)
{
case GDK_TOUCH_BEGIN:
if (gdk_device_get_source (gdk_event_get_source_device (event)) == GDK_SOURCE_TOUCHPAD)
klass = &GTK_SEQUENCE_TRACKER_CLASS_TOUCHPAD;
else
return NULL;
break;
default:
return NULL;
}
tracker = g_slice_new0 (GtkSequenceTracker);
tracker->klass = klass;
if (!tracker->klass->update (tracker, event, &tracker->start_x, &tracker->start_y))
{
g_assert_not_reached ();
return NULL;
}
time = gdk_event_get_time (event);
for (i = 0; i < GTK_SEQUENCE_TRACKER_HISTORY_SIZE; i++)
{
tracker->history[i].time = time;
tracker->history[i].x = tracker->start_x;
tracker->history[i].y = tracker->start_y;
tracker->history[i].dir = GTK_DIR_ANY;
}
tracker->history_index = 0;
return tracker;
}
void
_gtk_sequence_tracker_free (GtkSequenceTracker *tracker)
{
g_return_if_fail (tracker != NULL);
g_slice_free (GtkSequenceTracker, tracker);
}
static GtkMovementDirection
gtk_sequence_tracker_compute_direction (double dx,
double dy)
{
double r;
int i1, i2;
if (fabs (dx) < 2 && fabs (dy) < 2)
{
GtkMovementDirection dir = GTK_DIR_ANY;
if (dx <= 1)
dir &= GTK_DIR_SOUTH | GTK_DIR_SOUTH_WEST | GTK_DIR_WEST | GTK_DIR_NORTH_WEST | GTK_DIR_NORTH;
else if (dx >= 1)
dir &= GTK_DIR_SOUTH | GTK_DIR_SOUTH_EAST | GTK_DIR_EAST | GTK_DIR_NORTH_EAST | GTK_DIR_NORTH;
if (dy <= 1)
dir &= GTK_DIR_WEST | GTK_DIR_NORTH_WEST | GTK_DIR_NORTH | GTK_DIR_NORTH_EAST | GTK_DIR_EAST;
else
dir &= GTK_DIR_WEST | GTK_DIR_SOUTH_WEST | GTK_DIR_SOUTH | GTK_DIR_SOUTH_EAST | GTK_DIR_EAST;
return dir;
}
r = atan2(dy, dx);
/* Add 360° to avoid r become negative since C has no well-defined
* modulo for such cases. */
r += 2 * G_PI;
/* Divide by 45° to get the octant number, e.g.
* 0 <= r <= 1 is [0-45]°
* 1 <= r <= 2 is [45-90]°
* etc. */
r /= G_PI / 4;
/* This intends to flag 2 directions (45 degrees),
* except on very well-aligned coordinates. */
i1 = (int) (r + 0.1) % 8;
i2 = (int) (r + 0.9) % 8;
if (i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7)
return GTK_DIR_ANY;
return (1 << i1 | 1 << i2);
}
gboolean
_gtk_sequence_tracker_update (GtkSequenceTracker *tracker,
GdkEvent *event)
{
double x, y, dx, dy;
g_return_val_if_fail (tracker != NULL, FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if (!tracker->klass->update (tracker, event, &x, &y))
return FALSE;
dx = x - tracker->history[tracker->history_index].x;
dy = y - tracker->history[tracker->history_index].y;
tracker->history_index = (tracker->history_index + 1) % GTK_SEQUENCE_TRACKER_HISTORY_SIZE;
tracker->history[tracker->history_index].time = gdk_event_get_time (event);
tracker->history[tracker->history_index].x = x;
tracker->history[tracker->history_index].y = y;
tracker->history[tracker->history_index].dir = gtk_sequence_tracker_compute_direction (dx, dy);
return TRUE;
}
double
_gtk_sequence_tracker_get_x_offset (GtkSequenceTracker *tracker)
{
g_return_val_if_fail (tracker != NULL, 0);
return tracker->history[tracker->history_index].x
- tracker->start_x;
}
double
_gtk_sequence_tracker_get_y_offset (GtkSequenceTracker *tracker)
{
g_return_val_if_fail (tracker != NULL, 0);
return tracker->history[tracker->history_index].y
- tracker->start_y;
}
GtkMovementDirection
_gtk_sequence_tracker_get_direction (GtkSequenceTracker *tracker)
{
g_return_val_if_fail (tracker != NULL, GTK_DIR_ANY);
return tracker->history[tracker->history_index].dir;
}
void
_gtk_sequence_tracker_compute_distance (GtkSequenceTracker *from,
GtkSequenceTracker *to,
double *x,
double *y)
{
g_return_if_fail (from != NULL);
g_return_if_fail (to != NULL);
g_return_if_fail (from->klass == to->klass);
/* XXX: compare devices here? */
if (x)
*x = from->history[from->history_index].x - to->history[to->history_index].x;
if (y)
*y = from->history[from->history_index].y - to->history[to->history_index].y;
}

View File

@@ -0,0 +1,57 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2012 Benjamin Otte <otte@gnome.org>
*
* 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/>.
*/
#ifndef __GTK_SEQUENCE_TRACKER_PRIVATE_H__
#define __GTK_SEQUENCE_TRACKER_PRIVATE_H__
#include <gdk/gdk.h>
G_BEGIN_DECLS
typedef enum {
GTK_DIR_EAST = (1 << 0),
GTK_DIR_SOUTH_EAST = (1 << 1),
GTK_DIR_SOUTH = (1 << 2),
GTK_DIR_SOUTH_WEST = (1 << 3),
GTK_DIR_WEST = (1 << 4),
GTK_DIR_NORTH_WEST = (1 << 5),
GTK_DIR_NORTH = (1 << 6),
GTK_DIR_NORTH_EAST = (1 << 7),
GTK_DIR_ANY = (1 << 8) - 1,
} GtkMovementDirection;
typedef struct _GtkSequenceTracker GtkSequenceTracker;
GtkSequenceTracker * _gtk_sequence_tracker_new (GdkEvent *event);
void _gtk_sequence_tracker_free (GtkSequenceTracker *tracker);
gboolean _gtk_sequence_tracker_update (GtkSequenceTracker *tracker,
GdkEvent *event);
double _gtk_sequence_tracker_get_x_offset (GtkSequenceTracker *tracker);
double _gtk_sequence_tracker_get_y_offset (GtkSequenceTracker *tracker);
GtkMovementDirection _gtk_sequence_tracker_get_direction (GtkSequenceTracker *tracker);
void _gtk_sequence_tracker_compute_distance (GtkSequenceTracker *from,
GtkSequenceTracker *to,
double *x,
double *y);
G_END_DECLS
#endif /* __GTK_SEQUENCE_TRACKER_PRIVATE_H__ */

241
gtk/gtkswipegesture.c Normal file
View File

@@ -0,0 +1,241 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkswipegesture.h"
#include "gtksequencetrackerprivate.h"
#include "gtkswiperecognizer.h"
#include <math.h>
/**
* SECTION:gtkswipegesture
* @Short_description: Tracks the swipes from a #GtkSwipeRecognizer
* @Title: GtkSwipeGesture
* @See_also: #GtkSwipeRecognizer
*
* The #GtkSwipeGesture object - or a subclass of it - is used to track
* sequences of swipes as recognized by a #GtkSwipeRecognizer. Once the
* recognizer finds it can potentially identify a sequence of swipes, it
* creates a #GtkSwipeGesture and uses it to store information about the
* swipe. See the swipe handling howto for a highlevel overview.
*
* #GtkSwipeGesture was added in GTK 3.6.
*/
enum {
PROP_0,
};
struct _GtkSwipeGesturePrivate {
GtkSequenceTracker *sequence[2];
GtkMovementDirection direction;
};
G_DEFINE_TYPE (GtkSwipeGesture, gtk_swipe_gesture, GTK_TYPE_GESTURE)
static void
gtk_swipe_gesture_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
//GtkSwipeGesture *gesture = GTK_SWIPE_GESTURE (object);
//GtkSwipeGesturePrivate *priv = gesture->priv;
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_swipe_gesture_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
//GtkSwipeGesture *gesture = GTK_SWIPE_GESTURE (object);
//GtkSwipeGesturePrivate *priv = gesture->priv;
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_swipe_gesture_dispose (GObject *object)
{
//GtkSwipeGesture *gesture = GTK_SWIPE_GESTURE (object);
G_OBJECT_CLASS (gtk_swipe_gesture_parent_class)->dispose (object);
}
static void
gtk_swipe_gesture_class_init (GtkSwipeGestureClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_swipe_gesture_dispose;
object_class->set_property = gtk_swipe_gesture_set_property;
object_class->get_property = gtk_swipe_gesture_get_property;
g_type_class_add_private (object_class, sizeof (GtkSwipeGesturePrivate));
}
static void
gtk_swipe_gesture_init (GtkSwipeGesture *gesture)
{
GtkSwipeGesturePrivate *priv;
priv = gesture->priv = G_TYPE_INSTANCE_GET_PRIVATE (gesture,
GTK_TYPE_SWIPE_GESTURE,
GtkSwipeGesturePrivate);
priv->direction = GTK_DIR_ANY;
}
gboolean
_gtk_swipe_gesture_begin (GtkSwipeGesture *gesture,
GdkEvent *event)
{
GtkSwipeGesturePrivate *priv = gesture->priv;
if (priv->sequence[1] != NULL)
return FALSE;
if (priv->sequence[0] == NULL)
{
priv->sequence[0] = _gtk_sequence_tracker_new (event);
gtk_gesture_add_sequence (GTK_GESTURE (gesture), event->touch.sequence);
}
else
{
priv->sequence[1] = _gtk_sequence_tracker_new (event);
gtk_gesture_add_sequence (GTK_GESTURE (gesture), event->touch.sequence);
}
if (priv->sequence[1])
gtk_event_tracker_start (GTK_EVENT_TRACKER (gesture));
return FALSE;
}
gboolean
gtk_swipe_gesture_update_for_event (GtkSwipeGesture *gesture,
GdkEvent *event)
{
GtkSwipeGesturePrivate *priv = gesture->priv;
gboolean result = FALSE;
guint i;
for (i = 0; i < 2; i++)
{
if (priv->sequence[i] &&
_gtk_sequence_tracker_update (priv->sequence[i], event))
{
priv->direction &= _gtk_sequence_tracker_get_direction (priv->sequence[i]);
if (priv->direction == 0)
{
gtk_event_tracker_cancel (GTK_EVENT_TRACKER (gesture));
return FALSE;
}
result = TRUE;
}
}
return result;
}
gboolean
_gtk_swipe_gesture_update (GtkSwipeGesture *gesture,
GdkEvent *event)
{
if (gtk_swipe_gesture_update_for_event (gesture, event) &&
gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)))
gtk_event_tracker_update (GTK_EVENT_TRACKER (gesture));
return FALSE;
}
gboolean
_gtk_swipe_gesture_end (GtkSwipeGesture *gesture,
GdkEvent *event)
{
if (gtk_swipe_gesture_update_for_event (gesture, event))
{
if (gesture->priv->sequence[1])
gtk_event_tracker_finish (GTK_EVENT_TRACKER (gesture));
else
gtk_event_tracker_cancel (GTK_EVENT_TRACKER (gesture));
}
return FALSE;
}
gboolean
_gtk_swipe_gesture_cancel (GtkSwipeGesture *gesture,
GdkEvent *event)
{
if (gtk_swipe_gesture_update_for_event (gesture, event))
gtk_event_tracker_cancel (GTK_EVENT_TRACKER (gesture));
return FALSE;
}
void
gtk_swipe_gesture_get_offset (GtkSwipeGesture *gesture,
double *x,
double *y)
{
GtkSwipeGesturePrivate *priv;
g_return_if_fail (GTK_IS_SWIPE_GESTURE (gesture));
priv = gesture->priv;
if (!gtk_event_tracker_is_started (GTK_EVENT_TRACKER (gesture)) ||
gtk_event_tracker_is_cancelled (GTK_EVENT_TRACKER (gesture)))
{
if (x)
*x = 0;
if (y)
*y = 0;
return;
}
if (x)
*x = (_gtk_sequence_tracker_get_x_offset (priv->sequence[0])
+ _gtk_sequence_tracker_get_x_offset (priv->sequence[1])) / 2;
if (y)
*y = (_gtk_sequence_tracker_get_y_offset (priv->sequence[0])
+ _gtk_sequence_tracker_get_y_offset (priv->sequence[1])) / 2;
}

84
gtk/gtkswipegesture.h Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_SWIPE_GESTURE_H__
#define __GTK_SWIPE_GESTURE_H__
#include <gtk/gtkgesture.h>
G_BEGIN_DECLS
#define GTK_TYPE_SWIPE_GESTURE (gtk_swipe_gesture_get_type ())
#define GTK_SWIPE_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_SWIPE_GESTURE, GtkSwipeGesture))
#define GTK_SWIPE_GESTURE_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_SWIPE_GESTURE, GtkSwipeGestureClass))
#define GTK_IS_SWIPE_GESTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_SWIPE_GESTURE))
#define GTK_IS_SWIPE_GESTURE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_SWIPE_GESTURE))
#define GTK_SWIPE_GESTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SWIPE_GESTURE, GtkSwipeGestureClass))
typedef struct _GtkSwipeGesture GtkSwipeGesture;
typedef struct _GtkSwipeGestureClass GtkSwipeGestureClass;
typedef struct _GtkSwipeGesturePrivate GtkSwipeGesturePrivate;
struct _GtkSwipeGesture
{
GtkGesture parent;
GtkSwipeGesturePrivate *priv;
};
struct _GtkSwipeGestureClass
{
GtkGestureClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved0) (void);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_swipe_gesture_get_type (void) G_GNUC_CONST;
void gtk_swipe_gesture_get_offset (GtkSwipeGesture *gesture,
double *x,
double *y);
#include <gdk/gdk.h>
gboolean _gtk_swipe_gesture_begin (GtkSwipeGesture *gesture,
GdkEvent *event);
gboolean _gtk_swipe_gesture_update (GtkSwipeGesture *gesture,
GdkEvent *event);
gboolean _gtk_swipe_gesture_end (GtkSwipeGesture *gesture,
GdkEvent *event);
gboolean _gtk_swipe_gesture_cancel (GtkSwipeGesture *gesture,
GdkEvent *event);
G_END_DECLS
#endif /* __GTK_SWIPE_GESTURE_H__ */

95
gtk/gtkswiperecognizer.c Normal file
View File

@@ -0,0 +1,95 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkswiperecognizer.h"
#include "gtkswipegesture.h"
/**
* SECTION:gtkswiperecognizer
* @Short_description: Recognizes vertical and horizontal swipe gestures
* @Title: GtkSwipeRecognizer
* @See_also: #GtkSwipeGesture
*
* #GtkSwipeRecoginzer recognizes vertical and horizontal swipe gestures.
*
* #GtkSwipeRecognizer was added in GTK 3.6.
*/
G_DEFINE_TYPE (GtkSwipeRecognizer, gtk_swipe_recognizer, GTK_TYPE_GESTURE_RECOGNIZER)
static void
gtk_swipe_recognizer_recognize (GtkEventRecognizer *recognizer,
GtkWidget *widget,
GdkEvent *event)
{
if (event->type == GDK_TOUCH_BEGIN)
gtk_event_recognizer_create_tracker (recognizer, widget, event);
}
static gboolean
gtk_swipe_recognizer_track (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
GdkEvent *event)
{
GtkSwipeGesture *gesture = GTK_SWIPE_GESTURE (tracker);
switch (event->type)
{
case GDK_TOUCH_BEGIN:
return _gtk_swipe_gesture_begin (gesture, event);
case GDK_TOUCH_END:
return _gtk_swipe_gesture_end (gesture, event);
case GDK_TOUCH_UPDATE:
return _gtk_swipe_gesture_update (gesture, event);
case GDK_TOUCH_CANCEL:
return _gtk_swipe_gesture_cancel (gesture, event);
default:
return FALSE;
}
}
static void
gtk_swipe_recognizer_class_init (GtkSwipeRecognizerClass *klass)
{
GtkEventRecognizerClass *recognizer_class = GTK_EVENT_RECOGNIZER_CLASS (klass);
recognizer_class->recognize = gtk_swipe_recognizer_recognize;
recognizer_class->track = gtk_swipe_recognizer_track;
gtk_event_recognizer_class_set_event_mask (recognizer_class,
GDK_TOUCH_MASK);
gtk_event_recognizer_class_set_tracker_type (recognizer_class,
GTK_TYPE_SWIPE_GESTURE);
}
static void
gtk_swipe_recognizer_init (GtkSwipeRecognizer *recognizer)
{
}
GtkEventRecognizer *
gtk_swipe_recognizer_new (void)
{
return g_object_new (GTK_TYPE_SWIPE_RECOGNIZER, NULL);
}

72
gtk/gtkswiperecognizer.h Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright © 2012 Red Hat Inc.
*
* 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.1 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#ifndef __GTK_SWIPE_RECOGNIZER_H__
#define __GTK_SWIPE_RECOGNIZER_H__
#include <gtk/gtkgesturerecognizer.h>
G_BEGIN_DECLS
#define GTK_TYPE_SWIPE_RECOGNIZER (gtk_swipe_recognizer_get_type ())
#define GTK_SWIPE_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GTK_TYPE_SWIPE_RECOGNIZER, GtkSwipeRecognizer))
#define GTK_SWIPE_RECOGNIZER_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST (cls, GTK_TYPE_SWIPE_RECOGNIZER, GtkSwipeRecognizerClass))
#define GTK_IS_SWIPE_RECOGNIZER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GTK_TYPE_SWIPE_RECOGNIZER))
#define GTK_IS_SWIPE_RECOGNIZER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE (obj, GTK_TYPE_SWIPE_RECOGNIZER))
#define GTK_SWIPE_RECOGNIZER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SWIPE_RECOGNIZER, GtkSwipeRecognizerClass))
typedef struct _GtkSwipeRecognizer GtkSwipeRecognizer;
typedef struct _GtkSwipeRecognizerClass GtkSwipeRecognizerClass;
typedef struct _GtkSwipeRecognizerPrivate GtkSwipeRecognizerPrivate;
struct _GtkSwipeRecognizer
{
GtkGestureRecognizer parent;
GtkSwipeRecognizerPrivate *priv;
};
struct _GtkSwipeRecognizerClass
{
GtkGestureRecognizerClass parent_class;
/* Padding for future expansion */
void (*_gtk_reserved0) (void);
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
void (*_gtk_reserved4) (void);
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
};
GType gtk_swipe_recognizer_get_type (void) G_GNUC_CONST;
GtkEventRecognizer * gtk_swipe_recognizer_new (void);
G_END_DECLS
#endif /* __GTK_SWIPE_RECOGNIZER_H__ */

View File

@@ -29,10 +29,14 @@
#ifndef __GTK_TYPES_H__
#define __GTK_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _GtkAdjustment GtkAdjustment;
typedef struct _GtkClipboard GtkClipboard;
typedef struct _GtkEventRecognizer GtkEventRecognizer;
typedef struct _GtkEventTracker GtkEventTracker;
typedef struct _GtkIconSet GtkIconSet;
typedef struct _GtkIconSource GtkIconSource;
typedef struct _GtkRcStyle GtkRcStyle;

View File

@@ -35,6 +35,7 @@
#include "gtkcontainer.h"
#include "gtkaccelmapprivate.h"
#include "gtkclipboard.h"
#include "gtkeventrecognizerprivate.h"
#include "gtkiconfactory.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
@@ -401,6 +402,11 @@ struct _GtkWidgetPrivate
/* The widget's parent */
GtkWidget *parent;
/* The recognizers used by widget. Usually equal to the recognizers
* of its class, but can be modified.
*/
GPtrArray *recognizers;
#ifdef G_ENABLE_DEBUG
/* Number of gtk_widget_push_verify_invariants () */
guint verifying_invariants_count;
@@ -411,6 +417,7 @@ struct _GtkWidgetClassPrivate
{
GType accessible_type;
AtkRole accessible_role;
GPtrArray *recognizers;
};
enum {
@@ -542,7 +549,8 @@ struct _GtkStateData
static void gtk_widget_base_class_init (gpointer g_class);
static void gtk_widget_class_init (GtkWidgetClass *klass);
static void gtk_widget_base_class_finalize (GtkWidgetClass *klass);
static void gtk_widget_init (GtkWidget *widget);
static void gtk_widget_init (GTypeInstance *instance,
gpointer g_class);
static void gtk_widget_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -756,7 +764,7 @@ gtk_widget_get_type (void)
NULL, /* class_init */
sizeof (GtkWidget),
0, /* n_preallocs */
(GInstanceInitFunc) gtk_widget_init,
gtk_widget_init,
NULL, /* value_table */
};
@@ -792,8 +800,23 @@ static void
gtk_widget_base_class_init (gpointer g_class)
{
GtkWidgetClass *klass = g_class;
GtkWidgetClassPrivate *priv;
klass->priv = G_TYPE_CLASS_GET_PRIVATE (g_class, GTK_TYPE_WIDGET, GtkWidgetClassPrivate);
priv = klass->priv = G_TYPE_CLASS_GET_PRIVATE (g_class, GTK_TYPE_WIDGET, GtkWidgetClassPrivate);
if (priv->recognizers)
{
GPtrArray *copy;
guint i;
copy = g_ptr_array_new_full (priv->recognizers->len, g_object_unref);
for (i = 0; i < priv->recognizers->len; i++)
{
g_ptr_array_add (copy, g_object_ref (g_ptr_array_index (priv->recognizers, i)));
}
priv->recognizers = copy;
}
}
static void
@@ -3288,8 +3311,15 @@ gtk_widget_class_init (GtkWidgetClass *klass)
static void
gtk_widget_base_class_finalize (GtkWidgetClass *klass)
{
GtkWidgetClassPrivate *priv = klass->priv;
GList *list, *node;
if (priv->recognizers)
{
g_ptr_array_free (priv->recognizers, TRUE);
priv->recognizers = NULL;
}
list = g_param_spec_pool_list_owned (style_property_spec_pool, G_OBJECT_CLASS_TYPE (klass));
for (node = list; node; node = node->next)
{
@@ -3624,8 +3654,9 @@ gtk_widget_get_property (GObject *object,
}
static void
gtk_widget_init (GtkWidget *widget)
gtk_widget_init (GTypeInstance *instance, gpointer g_class)
{
GtkWidget *widget = GTK_WIDGET (instance);
GtkWidgetPrivate *priv;
widget->priv = G_TYPE_INSTANCE_GET_PRIVATE (widget,
@@ -3661,6 +3692,12 @@ gtk_widget_init (GtkWidget *widget)
priv->style = gtk_widget_get_default_style ();
g_object_ref (priv->style);
if (GTK_WIDGET_CLASS (g_class)->priv->recognizers)
{
priv->recognizers = GTK_WIDGET_CLASS (g_class)->priv->recognizers;
g_ptr_array_ref (priv->recognizers);
}
}
@@ -6258,6 +6295,30 @@ event_window_is_still_viewable (GdkEvent *event)
}
}
static gboolean
gtk_widget_invoke_recognizers (GtkWidget *widget,
GdkEvent *event)
{
GtkWidgetPrivate *priv = widget->priv;
guint i;
gboolean eat_event = FALSE;
if (priv->recognizers == NULL)
return FALSE;
g_object_ref (widget);
for (i = 0; i < priv->recognizers->len; i++)
{
GtkEventRecognizer *recognizer = g_ptr_array_index (priv->recognizers, i);
_gtk_event_recognizer_recognize (recognizer, widget, event);
}
g_object_unref (widget);
return eat_event;
}
static gint
gtk_widget_event_internal (GtkWidget *widget,
GdkEvent *event)
@@ -6272,6 +6333,8 @@ gtk_widget_event_internal (GtkWidget *widget,
if (!event_window_is_still_viewable (event))
return TRUE;
gtk_widget_invoke_recognizers (widget, event);
g_object_ref (widget);
g_signal_emit (widget, widget_signals[EVENT], 0, event, &return_val);
@@ -9551,6 +9614,27 @@ _gtk_widget_restore_size_request (GtkWidget *widget,
GTK_QUEUE_RESIZE_INVALIDATE_ONLY);
}
static gint
gtk_widget_get_recognizer_event_mask (GtkWidget *widget)
{
GtkWidgetPrivate *priv = widget->priv;
gint event_mask;
guint i;
if (priv->recognizers == NULL)
return 0;
event_mask = 0;
for (i = 0; i < priv->recognizers->len; i++)
{
event_mask |= gtk_event_recognizer_class_get_event_mask (
GTK_EVENT_RECOGNIZER_GET_CLASS (
g_ptr_array_index (priv->recognizers, i)));
}
return event_mask;
}
/**
* gtk_widget_set_events:
* @widget: a #GtkWidget
@@ -9978,9 +10062,14 @@ gtk_widget_get_settings (GtkWidget *widget)
gint
gtk_widget_get_events (GtkWidget *widget)
{
gint event_mask;
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
return GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (widget), quark_event_mask));
event_mask = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (widget), quark_event_mask));
event_mask |= gtk_widget_get_recognizer_event_mask (widget);
return event_mask;
}
/**
@@ -10373,6 +10462,12 @@ gtk_widget_real_destroy (GtkWidget *object)
g_object_unref (priv->style);
priv->style = gtk_widget_get_default_style ();
g_object_ref (priv->style);
if (priv->recognizers)
{
g_ptr_array_unref (priv->recognizers);
priv->recognizers = NULL;
}
}
static void
@@ -13778,6 +13873,161 @@ gtk_widget_send_focus_change (GtkWidget *widget,
return res;
}
/**
* gtk_widget_class_add_recognizer:
* @widget_class: The widget class
* @recognizer: The recognizer to add
*
* Adds @recognizer to @widget_class. The @recognizer will be
* added at the end of the list of recognizers.
*
* After calling this function, the properties of @recognizer
* should not be modified anymore.
*
* This function should only be called in the class_init function
* of @widget_class.
**/
void
gtk_widget_class_add_recognizer (GtkWidgetClass *widget_class,
GtkEventRecognizer *recognizer)
{
GtkWidgetClassPrivate *priv;
g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
g_return_if_fail (GTK_IS_EVENT_RECOGNIZER (recognizer));
priv = widget_class->priv;
if (priv->recognizers == NULL)
priv->recognizers = g_ptr_array_new_with_free_func (g_object_unref);
g_object_ref (recognizer);
g_ptr_array_add (priv->recognizers, recognizer);
}
static void
gtk_widget_ensure_custom_recognizers (GtkWidget *widget)
{
GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
GtkWidgetPrivate *priv = widget->priv;
GPtrArray *shared;
guint i;
shared = klass->priv->recognizers;
if (priv->recognizers != shared)
return;
priv->recognizers = g_ptr_array_new_with_free_func (g_object_unref);
if (shared == NULL)
return;
for (i = 0; i < shared->len; i++)
{
GtkEventRecognizer *recognizer;
recognizer = g_ptr_array_index (shared, i);
g_object_ref (recognizer);
g_ptr_array_add (priv->recognizers, recognizer);
}
g_object_unref (shared);
}
/**
* gtk_widget_add_recognizer:
* @widget: The widget
* @recognizer: The recognizer to add
*
* Adds @recognizer to @widget_class. The @recognizer will be
* added at the end of the list of recognizers.
**/
void
gtk_widget_add_recognizer (GtkWidget *widget,
GtkEventRecognizer *recognizer)
{
GtkWidgetPrivate *priv;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (GTK_IS_EVENT_RECOGNIZER (recognizer));
gtk_widget_ensure_custom_recognizers (widget);
priv = widget->priv;
g_object_ref (recognizer);
g_ptr_array_add (priv->recognizers, recognizer);
}
/**
* gtk_widget_remove_recognizer:
* @widget: The widget to remove the recognizer from
* @id: The index
*
* Removes the recognizer at @id from @widget.
**/
void
gtk_widget_remove_recognizer (GtkWidget *widget,
guint id)
{
GtkWidgetPrivate *priv;
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_widget_ensure_custom_recognizers (widget);
priv = widget->priv;
g_return_if_fail (id < priv->recognizers->len);
g_ptr_array_remove_index (priv->recognizers, id);
}
/**
* gtk_widget_get_recognizer:
* @widget: The widget
* @id: the index of the recognizer. Must be less then the number of
* recognizers of @widget.
*
* Gets the recognizer @id in use by @widget
*
* Returns: The recognizer
**/
GtkEventRecognizer *
gtk_widget_get_recognizer (GtkWidget *widget,
guint id)
{
GtkWidgetPrivate *priv;
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
priv = widget->priv;
g_return_val_if_fail (priv->recognizers != NULL, NULL);
g_return_val_if_fail (id < priv->recognizers->len, NULL);
return g_ptr_array_index (priv->recognizers, id);
}
/**
* gtk_widget_get_n_recognizers:
* @widget: the widget
*
* Gets the number of recognizers in use by @widget.
*
* Returns: The number of recognizers currently in use by @widget
**/
guint
gtk_widget_get_n_recognizers (GtkWidget *widget)
{
GtkWidgetPrivate *priv;
g_return_val_if_fail (GTK_IS_WIDGET_CLASS (widget), 0);
priv = widget->priv;
if (priv->recognizers == NULL)
return 0;
return priv->recognizers->len;
}
/**
* gtk_widget_in_destruction:
* @widget: a #GtkWidget

View File

@@ -526,6 +526,17 @@ gint gtk_widget_send_expose (GtkWidget *widget,
gboolean gtk_widget_send_focus_change (GtkWidget *widget,
GdkEvent *event);
void gtk_widget_class_add_recognizer(GtkWidgetClass *widget_class,
GtkEventRecognizer *recognizer);
void gtk_widget_add_recognizer (GtkWidget *widget,
GtkEventRecognizer *recognizer);
void gtk_widget_remove_recognizer (GtkWidget *widget,
guint id);
GtkEventRecognizer *
gtk_widget_get_recognizer (GtkWidget *widget,
guint id);
guint gtk_widget_get_n_recognizers (GtkWidget *widget);
gboolean gtk_widget_activate (GtkWidget *widget);
void gtk_widget_reparent (GtkWidget *widget,

View File

@@ -200,8 +200,8 @@ _gtk_win32_theme_part_create_surface (HTHEME theme,
cairo_t *cr;
int x_offs;
int y_offs;
gboolean has_alpha;
#ifdef G_OS_WIN32
gboolean has_alpha;
HDC hdc;
RECT rect;
SIZE size;

View File

@@ -55,6 +55,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testfontchooserdialog \
testframe \
testgeometry \
testgestures \
testgiconpixbuf \
testgrid \
testgtk \

View File

@@ -96,6 +96,10 @@ EXTRA_DIST += \
css-match-exact.css \
css-match-exact.ref.ui \
css-match-exact.ui \
css-match-import.css \
css-match-import-import.css \
css-match-import.ui \
css-match-import.ref.ui \
css-match-inherit.css \
css-match-inherit.ref.ui \
css-match-inherit.ui \

View File

@@ -0,0 +1,7 @@
GtkLabel {
color: blue;
}
#reference {
color: purple;
}

9
tests/reftests/css-match-import.css vendored Normal file
View File

@@ -0,0 +1,9 @@
@import url("css-match-import-import.css");
GtkLabel {
color: purple;
}
#reference {
color: purple;
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="type">popup</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="name">purple</property>
<property name="label" translatable="yes">Purple</property>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="type">popup</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Purple</property>
</object>
</child>
</object>
</interface>

238
tests/testgestures.c Normal file
View File

@@ -0,0 +1,238 @@
/*
* Copyright (C) 2012 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <gtk/gtk.h>
typedef struct _AreaData AreaData;
struct _AreaData {
double x_offset;
double y_offset;
double progress;
guint color;
cairo_matrix_t matrix;
cairo_matrix_t pending;
GdkPixbuf *pixbuf;
};
static void
update_swipe (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
AreaData *data)
{
GtkSwipeGesture *swipe = GTK_SWIPE_GESTURE (tracker);
GtkWidget *widget = gtk_event_tracker_get_widget (tracker);
double x, y;
gtk_swipe_gesture_get_offset (swipe, &x, &y);
x /= gtk_widget_get_allocated_width (widget);
y /= gtk_widget_get_allocated_height (widget);
data->x_offset = CLAMP (x, -1, 1);
data->y_offset = CLAMP (y, -1, 1);
gtk_widget_queue_draw (widget);
}
static void
finish_swipe (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
AreaData *data)
{
GtkSwipeGesture *swipe = GTK_SWIPE_GESTURE (tracker);
GtkWidget *widget = gtk_event_tracker_get_widget (tracker);
double x, y;
gtk_swipe_gesture_get_offset (swipe, &x, &y);
x /= gtk_widget_get_allocated_width (widget);
y /= gtk_widget_get_allocated_height (widget);
if (ABS (x) >= 0.5)
data->color ^= 1;
if (ABS (y) >= 0.5)
data->color ^= 2;
data->x_offset = 0;
data->y_offset = 0;
gtk_widget_queue_draw (widget);
}
static void
cancel_swipe (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
AreaData *data)
{
GtkWidget *widget = gtk_event_tracker_get_widget (tracker);
data->x_offset = 0;
data->y_offset = 0;
gtk_widget_queue_draw (widget);
}
static void
pinch_pan_get_matrix (cairo_matrix_t *matrix,
GtkPinchPanGesture *pinch)
{
double scale;
cairo_matrix_init_identity (matrix);
scale = gtk_pinch_pan_gesture_get_zoom (pinch);
cairo_matrix_translate (matrix,
gtk_pinch_pan_gesture_get_x_offset (pinch),
gtk_pinch_pan_gesture_get_y_offset (pinch));
cairo_matrix_scale (matrix, scale, scale);
cairo_matrix_rotate (matrix, gtk_pinch_pan_gesture_get_rotation (pinch) * G_PI / 180);
}
static void
update_pinch_pan (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
AreaData *data)
{
GtkPinchPanGesture *pinch = GTK_PINCH_PAN_GESTURE (tracker);
GtkWidget *widget = gtk_event_tracker_get_widget (tracker);
if (gtk_gesture_owns_all_sequences (GTK_GESTURE (tracker)))
pinch_pan_get_matrix (&data->pending, pinch);
gtk_widget_queue_draw (widget);
}
static void
finish_pinch_pan (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
AreaData *data)
{
GtkPinchPanGesture *pinch = GTK_PINCH_PAN_GESTURE (tracker);
GtkWidget *widget = gtk_event_tracker_get_widget (tracker);
pinch_pan_get_matrix (&data->pending, pinch);
cairo_matrix_multiply (&data->matrix, &data->matrix, &data->pending);
cairo_matrix_init_identity (&data->pending);
gtk_widget_queue_draw (widget);
}
static void
cancel_pinch_pan (GtkEventRecognizer *recognizer,
GtkEventTracker *tracker,
AreaData *data)
{
GtkWidget *widget = gtk_event_tracker_get_widget (tracker);
cairo_matrix_init_identity (&data->pending);
gtk_widget_queue_draw (widget);
}
static gboolean
draw_area (GtkWidget *widget,
cairo_t *cr,
AreaData *data)
{
static const GdkRGBA colors[4] = {
{ 1, 0, 0, 1 },
{ 0, 1, 0, 1 },
{ 0, 0, 1, 1 },
{ 1, 1, 0, 1 },
};
int i, x, y, w, h;
w = gtk_widget_get_allocated_width (widget);
h = gtk_widget_get_allocated_height (widget);
x = data->x_offset * w;
y = data->y_offset * h;
cairo_save (cr);
cairo_translate (cr, x, y);
for (i = 0; i < 4; i++)
{
gdk_cairo_set_source_rgba (cr, &colors[data->color ^ i]);
cairo_rectangle (cr,
i % 2 ? (x > 0 ? -w : w) : 0,
i / 2 ? (y > 0 ? -h : h) : 0,
w, h);
cairo_fill (cr);
}
cairo_restore (cr);
cairo_translate (cr,
gtk_widget_get_allocated_width (widget) / 2.0,
gtk_widget_get_allocated_height (widget) / 2.0);
cairo_transform (cr, &data->pending);
cairo_transform (cr, &data->matrix);
gdk_cairo_set_source_pixbuf (cr,
data->pixbuf,
- gdk_pixbuf_get_width (data->pixbuf) / 2.0,
- gdk_pixbuf_get_height (data->pixbuf) / 2.0);
cairo_paint (cr);
return FALSE;
}
int
main (int argc, char *argv[])
{
GtkEventRecognizer *recognizer;
GtkWidget *window, *area;
AreaData area_data = { 0 };
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
area = gtk_drawing_area_new ();
gtk_widget_set_has_window (area, TRUE);
gtk_widget_set_size_request (area, 400, 300);
recognizer = gtk_swipe_recognizer_new ();
g_signal_connect (recognizer, "started", G_CALLBACK (update_swipe), &area_data);
g_signal_connect (recognizer, "updated", G_CALLBACK (update_swipe), &area_data);
g_signal_connect (recognizer, "finished", G_CALLBACK (finish_swipe), &area_data);
g_signal_connect (recognizer, "cancelled", G_CALLBACK (cancel_swipe), &area_data);
gtk_widget_add_recognizer (area, recognizer);
cairo_matrix_init_identity (&area_data.matrix);
cairo_matrix_init_identity (&area_data.pending);
area_data.pixbuf = gdk_pixbuf_new_from_file ("gnome-textfile.png", NULL);
g_assert (area_data.pixbuf);
recognizer = gtk_pinch_pan_recognizer_new ();
g_signal_connect (recognizer, "started", G_CALLBACK (update_pinch_pan), &area_data);
g_signal_connect (recognizer, "updated", G_CALLBACK (update_pinch_pan), &area_data);
g_signal_connect (recognizer, "finished", G_CALLBACK (finish_pinch_pan), &area_data);
g_signal_connect (recognizer, "cancelled", G_CALLBACK (cancel_pinch_pan), &area_data);
gtk_widget_add_recognizer (area, recognizer);
g_signal_connect_after (area, "draw", G_CALLBACK (draw_area), &area_data);
gtk_container_add (GTK_CONTAINER (window), area);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}