Xamarin Public Jenkins (auto-signing) 6bdd276d05 Imported Upstream version 5.0.0.42
Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
2017-04-10 11:41:01 +00:00

736 lines
20 KiB
Diff

diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index e6c516c..f3fa26a 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -65,6 +65,11 @@ typedef struct _GdkEventWindowState GdkEventWindowState;
typedef struct _GdkEventSetting GdkEventSetting;
typedef struct _GdkEventGrabBroken GdkEventGrabBroken;
+/* OS X specific gesture events */
+typedef struct _GdkEventGestureMagnify GdkEventGestureMagnify;
+typedef struct _GdkEventGestureRotate GdkEventGestureRotate;
+typedef struct _GdkEventGestureSwipe GdkEventGestureSwipe;
+
typedef union _GdkEvent GdkEvent;
typedef void (*GdkEventFunc) (GdkEvent *event,
@@ -152,6 +157,9 @@ typedef enum
GDK_OWNER_CHANGE = 34,
GDK_GRAB_BROKEN = 35,
GDK_DAMAGE = 36,
+ GDK_GESTURE_MAGNIFY = 37,
+ GDK_GESTURE_ROTATE = 38,
+ GDK_GESTURE_SWIPE = 39,
GDK_EVENT_LAST /* helper variable for decls */
} GdkEventType;
@@ -488,6 +496,52 @@ struct _GdkEventDND {
gshort x_root, y_root;
};
+/* Event types for OS X gestures */
+
+struct _GdkEventGestureMagnify
+{
+ GdkEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ guint32 time;
+ gdouble x;
+ gdouble y;
+ guint state;
+ gdouble magnification;
+ GdkDevice *device;
+ gdouble x_root, y_root;
+};
+
+struct _GdkEventGestureRotate
+{
+ GdkEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ guint32 time;
+ gdouble x;
+ gdouble y;
+ guint state;
+ gdouble rotation;
+ GdkDevice *device;
+ gdouble x_root, y_root;
+};
+
+struct _GdkEventGestureSwipe
+{
+ GdkEventType type;
+ GdkWindow *window;
+ gint8 send_event;
+ guint32 time;
+ gdouble x;
+ gdouble y;
+ guint state;
+ gdouble delta_x;
+ gdouble delta_y;
+ GdkDevice *device;
+ gdouble x_root, y_root;
+};
+
+
union _GdkEvent
{
GdkEventType type;
@@ -511,6 +565,9 @@ union _GdkEvent
GdkEventWindowState window_state;
GdkEventSetting setting;
GdkEventGrabBroken grab_broken;
+ GdkEventGestureMagnify magnify;
+ GdkEventGestureRotate rotate;
+ GdkEventGestureSwipe swipe;
};
GType gdk_event_get_type (void) G_GNUC_CONST;
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index d20b424..fb89451 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -9813,6 +9813,9 @@ static const guint type_masks[] = {
0, /* GDK_OWNER_CHANGE = 34 */
0, /* GDK_GRAB_BROKEN = 35 */
0, /* GDK_DAMAGE = 36 */
+ 0, /* GDK_GESTURE_MAGNIFY = 37 */
+ 0, /* GDK_GESTURE_ROTATE = 38 */
+ 0, /* GDK_GESTURE_SWIPE = 39 */
};
G_STATIC_ASSERT (G_N_ELEMENTS (type_masks) == GDK_EVENT_LAST);
diff --git a/gdk/quartz/GdkQuartzView.c b/gdk/quartz/GdkQuartzView.c
index 2c897fb..cdae2f1 100644
--- a/gdk/quartz/GdkQuartzView.c
+++ b/gdk/quartz/GdkQuartzView.c
@@ -190,4 +190,37 @@
[self updateTrackingRect];
}
+/* Handle OS X gesture events. The Apple documentation is explicit
+ * that these events should not be captured through a tracking loop (which
+ * is how we handle usual event handling), so we fallback to overriding
+ * NSResponder methods.
+ */
+
+-(void)magnifyWithEvent:(NSEvent *)event
+{
+ GdkEvent *gdk_event;
+
+ gdk_event = _gdk_quartz_events_create_magnify_event (event);
+ if (gdk_event)
+ _gdk_event_queue_append (gdk_display_get_default (), gdk_event);
+}
+
+-(void)rotateWithEvent:(NSEvent *)event
+{
+ GdkEvent *gdk_event;
+
+ gdk_event = _gdk_quartz_events_create_rotate_event (event);
+ if (gdk_event)
+ _gdk_event_queue_append (gdk_display_get_default (), gdk_event);
+}
+
+-(void)swipeWithEvent:(NSEvent *)event
+{
+ GdkEvent *gdk_event;
+
+ gdk_event = _gdk_quartz_events_create_swipe_event (event);
+ if (gdk_event)
+ _gdk_event_queue_append (gdk_display_get_default (), gdk_event);
+}
+
@end
diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c
index 9478c16..128c794 100644
--- a/gdk/quartz/gdkevents-quartz.c
+++ b/gdk/quartz/gdkevents-quartz.c
@@ -374,6 +374,11 @@ get_event_mask_from_ns_event (NSEvent *nsevent)
case NSMouseExited:
return GDK_LEAVE_NOTIFY_MASK;
+ case NSEventTypeMagnify:
+ case NSEventTypeRotate:
+ case NSEventTypeSwipe:
+ return 0;
+
default:
g_assert_not_reached ();
}
@@ -752,6 +757,11 @@ find_window_for_ns_event (NSEvent *nsevent,
return toplevel;
+ case NSEventTypeMagnify:
+ case NSEventTypeRotate:
+ case NSEventTypeSwipe:
+ return toplevel;
+
default:
/* Ignore everything else. */
break;
@@ -1011,6 +1021,139 @@ fill_key_event (GdkWindow *window,
event->key.keyval));
}
+
+static GdkWindow *
+find_window_for_ns_gesture_event (NSEvent *nsevent,
+ gint *_x,
+ gint *_y,
+ gint *x_root,
+ gint *y_root)
+{
+ GdkDisplay *display = _gdk_display;
+ GdkWindow *toplevel_window = NULL, *pointer_window = NULL;
+ gdouble found_x, found_y;
+ gint x, y;
+
+ toplevel_window = find_window_for_ns_event (nsevent, &x, &y, x_root, y_root);
+ if (!toplevel_window)
+ return NULL;
+
+ if (toplevel_window == display->pointer_info.toplevel_under_pointer)
+ pointer_window = _gdk_window_find_descendant_at (toplevel_window,
+ x, y,
+ &found_x, &found_y);
+ else
+ pointer_window = NULL;
+
+ *_x = found_x;
+ *_y = found_y;
+
+ return pointer_window;
+}
+
+
+GdkEvent *
+_gdk_quartz_events_create_magnify_event (NSEvent *nsevent)
+{
+ GdkEvent *event;
+ GdkWindow *window = NULL;
+ gint x, y, x_root, y_root;
+
+ window = find_window_for_ns_gesture_event (nsevent,
+ &x, &y,
+ &x_root, &y_root);
+
+ if (!window)
+ return NULL;
+
+ event = gdk_event_new (GDK_GESTURE_MAGNIFY);
+
+ event->any.type = GDK_GESTURE_MAGNIFY;
+ event->magnify.window = window;
+ event->magnify.time = get_time_from_ns_event (nsevent);
+ event->magnify.x = x;
+ event->magnify.y = y;
+ event->magnify.x_root = x_root;
+ event->magnify.y_root = y_root;
+ event->magnify.magnification = [nsevent magnification];
+ event->magnify.state = get_keyboard_modifiers_from_ns_event (nsevent) |
+ _gdk_quartz_events_get_current_mouse_modifiers ();
+ event->magnify.device = _gdk_display->core_pointer;
+
+ fixup_event (event);
+
+ return event;
+}
+
+GdkEvent *
+_gdk_quartz_events_create_rotate_event (NSEvent *nsevent)
+{
+ GdkEvent *event;
+ GdkWindow *window;
+ gint x, y, x_root, y_root;
+
+ window = find_window_for_ns_gesture_event (nsevent,
+ &x, &y,
+ &x_root, &y_root);
+
+ if (!window)
+ return NULL;
+
+ event = gdk_event_new (GDK_GESTURE_ROTATE);
+
+ event->any.type = GDK_GESTURE_ROTATE;
+ event->rotate.window = window;
+ event->rotate.time = get_time_from_ns_event (nsevent);
+ event->rotate.x = x;
+ event->rotate.y = y;
+ event->rotate.x_root = x_root;
+ event->rotate.y_root = y_root;
+ event->rotate.rotation = [nsevent rotation];
+ event->rotate.state = get_keyboard_modifiers_from_ns_event (nsevent) |
+ _gdk_quartz_events_get_current_mouse_modifiers ();
+ event->rotate.device = _gdk_display->core_pointer;
+
+ fixup_event (event);
+
+ return event;
+}
+
+GdkEvent *
+_gdk_quartz_events_create_swipe_event (NSEvent *nsevent)
+{
+ GdkEvent *event;
+ GdkWindow *window;
+ gint x, y, x_root, y_root;
+
+ window = find_window_for_ns_gesture_event (nsevent,
+ &x, &y,
+ &x_root, &y_root);
+
+ if (!window)
+ return NULL;
+
+ event = gdk_event_new (GDK_GESTURE_SWIPE);
+
+ event->any.type = GDK_GESTURE_SWIPE;
+ event->swipe.window = window;
+ event->swipe.time = get_time_from_ns_event (nsevent);
+ event->swipe.x = x;
+ event->swipe.y = y;
+ event->swipe.x_root = x_root;
+ event->swipe.y_root = y_root;
+ event->swipe.delta_x = [nsevent deltaX];
+ event->swipe.delta_y = [nsevent deltaY];
+ event->swipe.state = get_keyboard_modifiers_from_ns_event (nsevent) |
+ _gdk_quartz_events_get_current_mouse_modifiers ();
+ event->swipe.device = _gdk_display->core_pointer;
+
+ fixup_event (event);
+
+ return event;
+}
+
+
+
static gboolean
synthesize_crossing_event (GdkWindow *window,
GdkEvent *event,
@@ -1392,6 +1535,13 @@ gdk_event_translate (GdkEvent *event,
}
break;
+ /* Gesture events are handled through GdkQuartzView, because the
+ * Apple documentation states very clearly that such events should
+ * not be handled through a tracking loop (like GDK uses).
+ * Experiments show that gesture events do not get through our
+ * tracking loop either.
+ */
+
default:
/* Ignore everything elsee. */
return_val = FALSE;
diff --git a/gdk/quartz/gdkglobals-quartz.c b/gdk/quartz/gdkglobals-quartz.c
index 53c6d5e..6d01b59 100644
--- a/gdk/quartz/gdkglobals-quartz.c
+++ b/gdk/quartz/gdkglobals-quartz.c
@@ -41,3 +41,9 @@ gdk_quartz_osx_version (void)
else
return minor;
}
+
+gboolean
+gdk_quartz_supports_gesture_events (void)
+{
+ return TRUE;
+}
diff --git a/gdk/quartz/gdkprivate-quartz.h b/gdk/quartz/gdkprivate-quartz.h
index c1b3083..03a3857 100644
--- a/gdk/quartz/gdkprivate-quartz.h
+++ b/gdk/quartz/gdkprivate-quartz.h
@@ -179,6 +179,10 @@ GdkModifierType _gdk_quartz_events_get_current_mouse_modifiers (void);
void _gdk_quartz_events_send_enter_notify_event (GdkWindow *window);
void _gdk_quartz_events_break_all_grabs (guint32 time);
+GdkEvent *_gdk_quartz_events_create_magnify_event (NSEvent *event);
+GdkEvent *_gdk_quartz_events_create_rotate_event (NSEvent *event);
+GdkEvent *_gdk_quartz_events_create_swipe_event (NSEvent *event);
+
/* Event loop */
gboolean _gdk_quartz_event_loop_check_pending (void);
NSEvent * _gdk_quartz_event_loop_get_pending (void);
diff --git a/gdk/quartz/gdkquartz.h b/gdk/quartz/gdkquartz.h
index 742d651..f79d04a 100644
--- a/gdk/quartz/gdkquartz.h
+++ b/gdk/quartz/gdkquartz.h
@@ -57,6 +57,7 @@ NSImage *gdk_quartz_pixbuf_to_ns_image_libgtk_only (GdkPixbuf
id gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext *context);
NSEvent *gdk_quartz_event_get_nsevent (GdkEvent *event);
GdkOSXVersion gdk_quartz_osx_version (void);
+gboolean gdk_quartz_supports_gesture_events (void);
G_END_DECLS
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 5a88679..db77675 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1636,6 +1636,9 @@ gtk_main_do_event (GdkEvent *event)
case GDK_WINDOW_STATE:
case GDK_GRAB_BROKEN:
case GDK_DAMAGE:
+ case GDK_GESTURE_MAGNIFY:
+ case GDK_GESTURE_ROTATE:
+ case GDK_GESTURE_SWIPE:
if (!_gtk_widget_captured_event (event_widget, event))
gtk_widget_event (event_widget, event);
break;
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 9a43d27..2d11e09 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -197,6 +197,9 @@ enum {
KEYNAV_FAILED,
DRAG_FAILED,
DAMAGE_EVENT,
+ GESTURE_MAGNIFY_EVENT,
+ GESTURE_ROTATE_EVENT,
+ GESTURE_SWIPE_EVENT,
LAST_SIGNAL
};
@@ -2242,6 +2245,70 @@ gtk_widget_class_init (GtkWidgetClass *klass)
_gtk_marshal_BOOLEAN__BOXED,
G_TYPE_BOOLEAN, 1,
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+ /**
+ * GtkWidget::gesture-magnify-event:
+ * @widget: the object which received the signal
+ * @event: the #GdkEventGestureMagnify event
+ *
+ * Emitted when a magnify event is received on @widget's window.
+ *
+ * Returns: %TRUE to stop other handlers from being invoked for the event.
+ * %FALSE to propagate the event further.
+ *
+ * Since: 2.24 Xamarin specific.
+ */
+ widget_signals[GESTURE_MAGNIFY_EVENT] =
+ g_signal_new (I_("gesture-magnify-event"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__BOXED,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+ /**
+ * GtkWidget::gesture-rotate-event:
+ * @widget: the object which received the signal
+ * @event: the #GdkEventGestureRotate event
+ *
+ * Emitted when a rotation event is received on @widget's window.
+ *
+ * Returns: %TRUE to stop other handlers from being invoked for the event.
+ * %FALSE to propagate the event further.
+ *
+ * Since: 2.24 Xamarin specific.
+ */
+ widget_signals[GESTURE_ROTATE_EVENT] =
+ g_signal_new (I_("gesture-rotate-event"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__BOXED,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+ /**
+ * GtkWidget::gesture-swipe-event:
+ * @widget: the object which received the signal
+ * @event: the #GdkEventGestureSwipe event
+ *
+ * Emitted when a swipe event is received on @widget's window.
+ *
+ * Returns: %TRUE to stop other handlers from being invoked for the event.
+ * %FALSE to propagate the event further.
+ *
+ * Since: 2.24 Xamarin specific.
+ */
+ widget_signals[GESTURE_SWIPE_EVENT] =
+ g_signal_new (I_("gesture-swipe-event"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__BOXED,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
/**
* GtkWidget::grab-broken-event:
* @widget: the object which received the signal
@@ -4975,6 +5042,15 @@ gtk_widget_event_internal (GtkWidget *widget,
case GDK_DAMAGE:
signal_num = DAMAGE_EVENT;
break;
+ case GDK_GESTURE_MAGNIFY:
+ signal_num = GESTURE_MAGNIFY_EVENT;
+ break;
+ case GDK_GESTURE_ROTATE:
+ signal_num = GESTURE_ROTATE_EVENT;
+ break;
+ case GDK_GESTURE_SWIPE:
+ signal_num = GESTURE_SWIPE_EVENT;
+ break;
default:
g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
signal_num = -1;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3888826..68a0a79 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -88,7 +88,8 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testactions \
testgrouping \
testtooltips \
- testvolumebutton
+ testvolumebutton \
+ testgestures
if HAVE_CXX
noinst_PROGRAMS += autotestkeywords
@@ -165,6 +166,7 @@ testgrouping_DEPENDENCIES = $(TEST_DEPS)
testtooltips_DEPENDENCIES = $(TEST_DEPS)
testvolumebutton_DEPENDENCIES = $(TEST_DEPS)
testwindows_DEPENDENCIES = $(TEST_DEPS)
+testgestures_DEPENDENCIES = $(TEST_DEPS)
testentrycompletion_SOURCES = \
prop-editor.c \
@@ -273,6 +275,9 @@ testoffscreenwindow_SOURCES = \
testwindows_SOURCES = \
testwindows.c
+testgestures_SOURCES = \
+ testgestures.c
+
EXTRA_DIST += \
prop-editor.h \
testgtk.1 \
diff --git a/tests/testgestures.c b/tests/testgestures.c
new file mode 100644
index 0000000..ae3ab99
--- /dev/null
+++ b/tests/testgestures.c
@@ -0,0 +1,214 @@
+#include <gtk/gtk.h>
+#include <math.h>
+
+
+typedef struct
+{
+ gdouble width;
+ gdouble height;
+
+ gdouble angle;
+
+ GtkWidget *widget;
+ gint offset_x;
+ gint offset_y;
+ gdouble progress;
+ gboolean increasing;
+}
+RectangleInfo;
+
+
+
+static gboolean
+handle_expose_event (GtkWidget *widget,
+ GdkEventExpose *expose,
+ gpointer user_data)
+{
+ cairo_t *cr;
+ int center_x, center_y;
+ RectangleInfo *rect = (RectangleInfo *)user_data;
+
+ cr = gdk_cairo_create (widget->window);
+
+ cairo_save (cr);
+
+ /* Background */
+ cairo_rectangle (cr, 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_fill (cr);
+
+ cairo_restore (cr);
+
+ /* Rectangle */
+ center_x = (widget->allocation.width - rect->width) / 2;
+ center_y = (widget->allocation.height - rect->height) / 2;
+
+ if (rect->progress != 0.0f)
+ {
+ cairo_translate (cr, rect->offset_x * rect->progress,
+ rect->offset_y * rect->progress);
+ }
+
+ cairo_save (cr);
+
+ cairo_translate (cr, widget->allocation.width / 2,
+ widget->allocation.height / 2);
+ cairo_rotate (cr, rect->angle * M_PI / 180.0);
+ cairo_translate (cr, -widget->allocation.width / 2,
+ -widget->allocation.height / 2);
+
+
+ cairo_rectangle (cr,
+ center_x, center_y,
+ rect->width, rect->height);
+ cairo_set_source_rgb (cr, 0.9, 0.0, 0.0);
+ cairo_stroke (cr);
+
+ cairo_rectangle (cr,
+ center_x, center_y,
+ rect->width, rect->height);
+ cairo_set_source_rgba (cr, 0.9, 0.0, 0.0, 0.3);
+ cairo_fill (cr);
+
+ cairo_restore (cr);
+
+
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+static gboolean
+handle_gesture_magnify_event (GtkWidget *widget,
+ GdkEventGestureMagnify *magnify,
+ gpointer user_data)
+{
+ RectangleInfo *rect = (RectangleInfo *)user_data;
+
+ rect->width += rect->width * magnify->magnification;
+ if (rect->width < 5)
+ rect->width = 5;
+
+ rect->height += rect->height * magnify->magnification;
+ if (rect->height < 5)
+ rect->height = 5;
+
+ gtk_widget_queue_draw (widget);
+
+ return TRUE;
+}
+
+static gboolean
+handle_gesture_rotate_event (GtkWidget *widget,
+ GdkEventGestureRotate *rotate,
+ gpointer user_data)
+{
+ RectangleInfo *rect = (RectangleInfo *)user_data;
+
+ rect->angle -= rotate->rotation;
+
+ gtk_widget_queue_draw (widget);
+
+ return TRUE;
+}
+
+
+static gboolean
+bounce_timeout (gpointer user_data)
+{
+ gboolean retval = TRUE;
+ RectangleInfo *rect = (RectangleInfo *)user_data;
+
+ if (rect->increasing)
+ rect->progress += 0.10f;
+ else
+ rect->progress -= 0.10f;
+
+ if (rect->progress > 1.0f)
+ {
+ rect->progress = 0.90f;
+ rect->increasing = FALSE;
+ }
+ else if (rect->progress <= 0.0f)
+ {
+ rect->progress = 0.0f;
+ retval = FALSE;
+ }
+
+ gtk_widget_queue_draw (rect->widget);
+
+ return retval;
+}
+
+static void
+bounce (RectangleInfo *rect,
+ int offset_x,
+ int offset_y)
+{
+ if (rect->progress != 0.0f)
+ return;
+
+ rect->progress = 0.10f;
+ rect->increasing = TRUE;
+ rect->offset_x = offset_x;
+ rect->offset_y = offset_y;
+ gtk_widget_queue_draw (rect->widget);
+
+ gdk_threads_add_timeout (25, bounce_timeout, rect);
+}
+
+static gboolean
+handle_gesture_swipe_event (GtkWidget *widget,
+ GdkEventGestureSwipe *swipe,
+ gpointer user_data)
+{
+ int offset_x = 150, offset_y = 150;
+ RectangleInfo *rect = (RectangleInfo *)user_data;
+
+ offset_x *= -1.0 * swipe->delta_x;
+ offset_y *= -1.0 * swipe->delta_y;
+
+ bounce (rect, offset_x, offset_y);
+
+ return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *window;
+ GtkWidget *drawing_area;
+ RectangleInfo rect;
+
+ gtk_init (&argc, &argv);
+
+ rect.width = 40.0;
+ rect.height = 40.0;
+ rect.angle = 0.0;
+ rect.progress = 0.0f;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
+ g_signal_connect (window, "delete-event",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+ drawing_area = gtk_drawing_area_new ();
+ rect.widget = drawing_area;
+ g_signal_connect (drawing_area, "expose-event",
+ G_CALLBACK (handle_expose_event), &rect);
+ g_signal_connect (drawing_area, "gesture-magnify-event",
+ G_CALLBACK (handle_gesture_magnify_event), &rect);
+ g_signal_connect (drawing_area, "gesture-rotate-event",
+ G_CALLBACK (handle_gesture_rotate_event), &rect);
+ g_signal_connect (drawing_area, "gesture-swipe-event",
+ G_CALLBACK (handle_gesture_swipe_event), &rect);
+ gtk_container_add (GTK_CONTAINER (window), drawing_area);
+
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}