r3062 - in trunk/src/target/OM-2007.2/libraries/libmokoui2: . libmokoui
chris at sita.openmoko.org
chris at sita.openmoko.org
Mon Oct 1 12:51:13 CEST 2007
Author: chris
Date: 2007-10-01 12:51:12 +0200 (Mon, 01 Oct 2007)
New Revision: 3062
Modified:
trunk/src/target/OM-2007.2/libraries/libmokoui2/ChangeLog
trunk/src/target/OM-2007.2/libraries/libmokoui2/libmokoui/moko-finger-scroll.c
Log:
* libmokoui/moko-finger-scroll.c:
Change the way events are synthesised to enable dragging (and thus
text selection) in a scroll widget
Modified: trunk/src/target/OM-2007.2/libraries/libmokoui2/ChangeLog
===================================================================
--- trunk/src/target/OM-2007.2/libraries/libmokoui2/ChangeLog 2007-09-30 20:12:17 UTC (rev 3061)
+++ trunk/src/target/OM-2007.2/libraries/libmokoui2/ChangeLog 2007-10-01 10:51:12 UTC (rev 3062)
@@ -1,3 +1,13 @@
+2007-10-01 Chris Lord <chris at openedhand.com>
+
+ * libmokoui/moko-finger-scroll.c: (moko_finger_scroll_get_topmost),
+ (synth_crossing), (moko_finger_scroll_button_press_cb),
+ (moko_finger_scroll_motion_notify_cb),
+ (moko_finger_scroll_button_release_cb), (moko_finger_scroll_add),
+ (moko_finger_scroll_add_with_viewport):
+ Change the way events are synthesised to enable dragging (and thus
+ text selection) in a scroll widget
+
2007-09-27 Chris Lord <chris at openedhand.com>
* libmokoui/moko-hint-entry.c: (moko_hint_entry_set_text):
Modified: trunk/src/target/OM-2007.2/libraries/libmokoui2/libmokoui/moko-finger-scroll.c
===================================================================
--- trunk/src/target/OM-2007.2/libraries/libmokoui2/libmokoui/moko-finger-scroll.c 2007-09-30 20:12:17 UTC (rev 3061)
+++ trunk/src/target/OM-2007.2/libraries/libmokoui2/libmokoui/moko-finger-scroll.c 2007-10-01 10:51:12 UTC (rev 3062)
@@ -28,23 +28,30 @@
*
*/
+/* TODO:
+ * - Scroll policies
+ * - Delay click mode (only send synthetic clicks on mouse-up, as in previous
+ * versions.
+ * - 'Physical' mode for acceleration scrolling
+ */
#include "moko-finger-scroll.h"
G_DEFINE_TYPE (MokoFingerScroll, moko_finger_scroll, GTK_TYPE_EVENT_BOX)
#define FINGER_SCROLL_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), MOKO_TYPE_FINGER_SCROLL, MokoFingerScrollPrivate))
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), MOKO_TYPE_FINGER_SCROLL, \
+ MokoFingerScrollPrivate))
typedef struct _MokoFingerScrollPrivate MokoFingerScrollPrivate;
struct _MokoFingerScrollPrivate {
MokoFingerScrollMode mode;
- gdouble x;
- gdouble y;
- gdouble ex;
- gdouble ey;
+ gdouble x; /* Used to store mouse co-ordinates of the first or */
+ gdouble y; /* previous events in a press-motion pair */
+ gdouble ex; /* Used to store mouse co-ordinates of the last */
+ gdouble ey; /* motion event in acceleration mode */
gboolean enabled;
gboolean clicked;
- guint32 last_time;
+ guint32 last_time; /* Last event time, to stop infinite loops */
gboolean moved;
GTimeVal click_start;
gdouble vmin;
@@ -53,6 +60,11 @@
guint sps;
gdouble vel_x;
gdouble vel_y;
+ GdkWindow *child;
+ gint ix; /* Initial click mouse co-ordinates */
+ gint iy;
+ gint cx; /* Initial click child window mouse co-ordinates */
+ gint cy;
GtkWidget *align;
gboolean hscroll;
@@ -74,11 +86,88 @@
PROP_SPS,
};
+static GdkWindow *
+moko_finger_scroll_get_topmost (GdkWindow *window, gint x, gint y,
+ gint *tx, gint *ty)
+{
+ /* Find the GdkWindow at the given point, by recursing from a given
+ * parent GdkWindow. Optionally return the co-ordinates transformed
+ * relative to the child window.
+ */
+ gint width, height;
+
+ gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
+ if ((x < 0) || (x >= width) || (y < 0) || (y >= height)) return NULL;
+
+ /*g_debug ("Finding window at (%d, %d) in %p", x, y, window);*/
+
+ while (window) {
+ gint child_x, child_y;
+ GList *c, *children = gdk_window_peek_children (window);
+ GdkWindow *old_window = window;
+ for (c = children; c; c = c->next) {
+ GdkWindow *child = (GdkWindow *)c->data;
+ gint wx, wy;
+
+ gdk_window_get_geometry (child, &wx, &wy,
+ &width, &height, NULL);
+ /*g_debug ("Child: %p, (%dx%d+%d,%d)", child,
+ width, height, wx, wy);*/
+
+ if ((x >= wx) && (x < (wx + width)) &&
+ (y >= wy) && (y < (wy + height))) {
+ child_x = x - wx; child_y = y - wy;
+ window = child;
+ }
+ }
+ /*g_debug ("\\|/");*/
+ if (window == old_window) break;
+
+ x = child_x;
+ y = child_y;
+ }
+
+ if (tx) *tx = x;
+ if (ty) *ty = y;
+
+ /*g_debug ("Returning: %p", window);*/
+
+ return window;
+}
+
+static void
+synth_crossing (GdkWindow *child, gint x, gint y, gint x_root, gint y_root,
+ guint32 time, gboolean in)
+{
+ GdkEventCrossing *crossing_event;
+ GdkEventType type = in ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
+
+ /* Send synthetic enter event */
+ crossing_event = (GdkEventCrossing *)gdk_event_new (type);
+ ((GdkEventAny *)crossing_event)->type = type;
+ ((GdkEventAny *)crossing_event)->window = g_object_ref (child);
+ ((GdkEventAny *)crossing_event)->send_event = FALSE;
+ crossing_event->subwindow = g_object_ref (child);
+ crossing_event->time = time;
+ crossing_event->x = x;
+ crossing_event->y = y;
+ crossing_event->x_root = x_root;
+ crossing_event->y_root = y_root;
+ crossing_event->mode = GDK_CROSSING_NORMAL;
+ crossing_event->detail = GDK_NOTIFY_UNKNOWN;
+ crossing_event->focus = FALSE;
+ crossing_event->state = 0;
+ gdk_event_put ((GdkEvent *)crossing_event);
+ gdk_event_free ((GdkEvent *)crossing_event);
+}
+
static gboolean
moko_finger_scroll_button_press_cb (MokoFingerScroll *scroll,
GdkEventButton *event,
gpointer user_data)
{
+ gint x, y;
+
MokoFingerScrollPrivate *priv = FINGER_SCROLL_PRIVATE (scroll);
if ((!priv->enabled) || (priv->clicked) || (event->button != 1) ||
@@ -88,18 +177,42 @@
priv->last_time = event->time;
priv->x = event->x;
priv->y = event->y;
+ priv->ix = priv->x;
+ priv->iy = priv->y;
/* Don't allow a click if we're still moving fast, where fast is
* defined as a quarter of our top possible speed.
* TODO: Make 'fast' configurable?
*/
if ((ABS (priv->vel_x) < (priv->vmax * 0.25)) &&
(ABS (priv->vel_y) < (priv->vmax * 0.25)))
- priv->moved = FALSE;
+ priv->child = moko_finger_scroll_get_topmost (
+ GTK_BIN (priv->align)->child->window,
+ event->x, event->y, &x, &y);
+ else
+ priv->child = NULL;
+
priv->clicked = TRUE;
/* Stop scrolling on mouse-down (so you can flick, then hold to stop) */
priv->vel_x = 0;
priv->vel_y = 0;
+ if ((priv->child) && (priv->child != GTK_BIN (
+ priv->align)->child->window)) {
+ event->x = x;
+ event->y = y;
+ priv->cx = x;
+ priv->cy = y;
+ if (event->type == GDK_2BUTTON_PRESS) g_debug ("Double click");
+
+ synth_crossing (priv->child, x, y, event->x_root,
+ event->y_root, event->time, TRUE);
+
+ /* Send synthetic click (button press/release) event */
+ ((GdkEventAny *)event)->window = g_object_ref (priv->child);
+ gdk_event_put ((GdkEvent *)event);
+ } else
+ priv->child = NULL;
+
return TRUE;
}
@@ -255,8 +368,9 @@
gint dnd_threshold;
gdouble x, y;
- if ((!priv->enabled) || (!priv->clicked)) return FALSE;
-
+ if ((!priv->enabled) || (!priv->clicked) ||
+ (event->time == priv->last_time)) return FALSE;
+
/* Only start the scroll if the mouse cursor passes beyond the
* DnD threshold for dragging.
*/
@@ -305,60 +419,22 @@
}
}
+ if (priv->child) {
+ /* Send motion notify to child */
+ gint wx, wy;
+ priv->last_time = event->time;
+ gdk_window_get_position (priv->child, &wx, &wy);
+ event->x = priv->cx + (event->x - priv->ix);
+ event->y = priv->cy + (event->y - priv->iy);
+ event->window = g_object_ref (priv->child);
+ gdk_event_put ((GdkEvent *)event);
+ }
+
gdk_window_get_pointer (GTK_WIDGET (scroll)->window, NULL, NULL, 0);
return TRUE;
}
-static GdkWindow *
-moko_finger_scroll_get_topmost (GdkWindow *window, gint x, gint y,
- gint *tx, gint *ty)
-{
- /* Find the GdkWindow at the given point, by recursing from a given
- * parent GdkWindow. Optionally return the co-ordinates transformed
- * relative to the child window.
- */
- gint width, height;
-
- gdk_drawable_get_size (GDK_DRAWABLE (window), &width, &height);
- if ((x < 0) || (x >= width) || (y < 0) || (y >= height)) return NULL;
-
- /*g_debug ("Finding window at (%d, %d) in %p", x, y, window);*/
-
- while (window) {
- gint child_x, child_y;
- GList *c, *children = gdk_window_peek_children (window);
- GdkWindow *old_window = window;
- for (c = children; c; c = c->next) {
- GdkWindow *child = (GdkWindow *)c->data;
- gint wx, wy;
-
- gdk_window_get_geometry (child, &wx, &wy,
- &width, &height, NULL);
- /*g_debug ("Child: %p, (%dx%d+%d,%d)", child,
- width, height, wx, wy);*/
-
- if ((x >= wx) && (x < (wx + width)) &&
- (y >= wy) && (y < (wy + height))) {
- child_x = x - wx; child_y = y - wy;
- window = child;
- }
- }
- /*g_debug ("\\|/");*/
- if (window == old_window) break;
-
- x = child_x;
- y = child_y;
- }
-
- if (tx) *tx = x;
- if (ty) *ty = y;
-
- /*g_debug ("Returning: %p", window);*/
-
- return window;
-}
-
static gboolean
moko_finger_scroll_button_release_cb (MokoFingerScroll *scroll,
GdkEventButton *event,
@@ -366,6 +442,8 @@
{
MokoFingerScrollPrivate *priv = FINGER_SCROLL_PRIVATE (scroll);
GTimeVal current;
+ gint x, y;
+ GdkWindow *child;
if ((!priv->clicked) || (!priv->enabled) || (event->button != 1) ||
(event->time == priv->last_time))
@@ -375,63 +453,33 @@
g_get_current_time (¤t);
priv->clicked = FALSE;
- if ((!priv->moved) &&
- (!(current.tv_sec > priv->click_start.tv_sec))/* &&
- (!(current.tv_usec - priv->click_start.tv_usec > 500000))*/) {
- gint x, y;
- GdkEventCrossing *crossing_event;
- GdkWindow *child;
+ priv->moved = FALSE;
- child = moko_finger_scroll_get_topmost (
- GTK_BIN (priv->align)->child->window,
- event->x, event->y, &x, &y);
+ child = moko_finger_scroll_get_topmost (
+ GTK_BIN (priv->align)->child->window,
+ event->x, event->y, &x, &y);
- if ((!child) || (child == GTK_BIN (priv->align)->child->window))
- return TRUE;
+ event->x = x;
+ event->y = y;
- event->x = x;
- event->y = y;
-
- /* Set velocity to zero, most widgets don't expect to be
- * moving while being clicked.
- */
- priv->vel_x = 0;
- priv->vel_y = 0;
-
- /* Send synthetic enter event */
- crossing_event = (GdkEventCrossing *)
- gdk_event_new (GDK_ENTER_NOTIFY);
- ((GdkEventAny *)crossing_event)->type = GDK_ENTER_NOTIFY;
- ((GdkEventAny *)crossing_event)->window = g_object_ref (child);
- ((GdkEventAny *)crossing_event)->send_event = FALSE;
- crossing_event->subwindow = g_object_ref (child);
- crossing_event->time = event->time;
- crossing_event->x = event->x;
- crossing_event->y = event->y;
- crossing_event->x_root = event->x_root;
- crossing_event->y_root = event->y_root;
- crossing_event->mode = GDK_CROSSING_NORMAL;
- crossing_event->detail = GDK_NOTIFY_UNKNOWN;
- crossing_event->focus = FALSE;
- crossing_event->state = 0;
- gdk_event_put ((GdkEvent *)crossing_event);
-
- /* Send synthetic click (button press/release) event */
- ((GdkEventAny *)event)->window = g_object_ref (child);
- ((GdkEventAny *)event)->type = GDK_BUTTON_PRESS;
+ if (!priv->child) return TRUE;
+
+ if (child != priv->child) {
+ g_debug ("Crossing/clicking out");
+ /* Send synthetic leave event */
+ synth_crossing (priv->child, x, y, event->x_root,
+ event->y_root, event->time, FALSE);
+ /* Send synthetic button release event */
+ ((GdkEventAny *)event)->window = g_object_ref (priv->child);
gdk_event_put ((GdkEvent *)event);
+ } else {
+ g_debug ("Clicking in");
+ /* Send synthetic button release event */
((GdkEventAny *)event)->window = g_object_ref (child);
- ((GdkEventAny *)event)->type = GDK_BUTTON_RELEASE;
gdk_event_put ((GdkEvent *)event);
-
/* Send synthetic leave event */
- ((GdkEventAny *)crossing_event)->type = GDK_LEAVE_NOTIFY;
- ((GdkEventAny *)crossing_event)->window = g_object_ref (child);
- crossing_event->subwindow = g_object_ref (child);
- crossing_event->window = g_object_ref (child);
- crossing_event->detail = GDK_NOTIFY_UNKNOWN;
- gdk_event_put ((GdkEvent *)crossing_event);
- gdk_event_free ((GdkEvent *)crossing_event);
+ synth_crossing (priv->child, x, y, event->x_root,
+ event->y_root, event->time, FALSE);
}
return TRUE;
@@ -543,8 +591,10 @@
g_signal_connect_swapped (G_OBJECT (child), "size-request",
G_CALLBACK (gtk_widget_queue_resize), container);
- if (!gtk_widget_set_scroll_adjustments (child, priv->hadjust, priv->vadjust))
- g_warning("%s: cannot add non scrollable widget, wrap it in a viewport", __FUNCTION__);
+ if (!gtk_widget_set_scroll_adjustments (
+ child, priv->hadjust, priv->vadjust))
+ g_warning("%s: cannot add non scrollable widget, "
+ "wrap it in a viewport", __FUNCTION__);
}
static void
@@ -846,7 +896,8 @@
*/
void
-moko_finger_scroll_add_with_viewport (MokoFingerScroll *scroll, GtkWidget *child)
+moko_finger_scroll_add_with_viewport (MokoFingerScroll *scroll,
+ GtkWidget *child)
{
GtkWidget *viewport = gtk_viewport_new (NULL, NULL);
gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
More information about the commitlog
mailing list