mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-04-28 12:17:57 +03:00
View: add basic implemntation of dispatchTouchEvent
Some Views block all events going to their descendants, and then synthesize new events themselves. Gtk doesn't allow event synthesization, which makes this quite annoying to deal with. This initial implementation definiely has some problems, for example it seems to cause infinite loops in some cases, however it surprisingly works well enough.
This commit is contained in:
parent
b19f2c35d2
commit
4d12ad5c90
9 changed files with 518 additions and 24 deletions
|
@ -231,6 +231,14 @@ JNIEXPORT void JNICALL Java_android_view_ViewGroup_native_1drawChildren
|
|||
JNIEXPORT void JNICALL Java_android_view_ViewGroup_native_1drawChild
|
||||
(JNIEnv *, jobject, jlong, jlong, jlong);
|
||||
|
||||
/*
|
||||
* Class: android_view_ViewGroup
|
||||
* Method: native_dispatchTouchEvent
|
||||
* Signature: (JLandroid/view/MotionEvent;DD)Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_android_view_ViewGroup_native_1dispatchTouchEvent
|
||||
(JNIEnv *, jobject, jlong, jobject, jdouble, jdouble);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -132,6 +132,7 @@ void set_up_handle_cache(JNIEnv *env)
|
|||
handle_cache.view.getScrollY = _METHOD(handle_cache.view.class, "getScrollY", "()I");
|
||||
handle_cache.view.performClick = _METHOD(handle_cache.view.class, "performClick", "()Z");
|
||||
handle_cache.view.onTouchEvent = _METHOD(handle_cache.view.class, "onTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||
handle_cache.view.onTouchEventInternal = _METHOD(handle_cache.view.class, "onTouchEventInternal", "(Landroid/view/MotionEvent;)Z");
|
||||
handle_cache.view.dispatchTouchEvent = _METHOD(handle_cache.view.class, "dispatchTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||
handle_cache.view.onInterceptTouchEvent = _METHOD(handle_cache.view.class, "onInterceptTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||
handle_cache.view.layoutInternal = _METHOD(handle_cache.view.class, "layoutInternal", "(II)V");
|
||||
|
@ -143,6 +144,9 @@ void set_up_handle_cache(JNIEnv *env)
|
|||
handle_cache.view.dispatchKeyEvent = _METHOD(handle_cache.view.class, "dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z");
|
||||
handle_cache.view.onKeyDown = _METHOD(handle_cache.view.class, "onKeyDown", "(ILandroid/view/KeyEvent;)Z");
|
||||
|
||||
handle_cache.view_group.class = _REF((*env)->FindClass(env, "android/view/ViewGroup"));
|
||||
handle_cache.view_group.dispatchTouchEvent = _METHOD(handle_cache.view_group.class, "dispatchTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||
|
||||
handle_cache.asset_manager.class = _REF((*env)->FindClass(env, "android/content/res/AssetManager"));
|
||||
handle_cache.asset_manager.extractFromAPK = _STATIC_METHOD(handle_cache.asset_manager.class, "extractFromAPK", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ struct handle_cache {
|
|||
jmethodID getScrollY;
|
||||
jmethodID performClick;
|
||||
jmethodID onTouchEvent;
|
||||
jmethodID onTouchEventInternal;
|
||||
jmethodID dispatchTouchEvent;
|
||||
jmethodID onInterceptTouchEvent;
|
||||
jmethodID layoutInternal;
|
||||
|
@ -88,6 +89,10 @@ struct handle_cache {
|
|||
jmethodID dispatchKeyEvent;
|
||||
jmethodID onKeyDown;
|
||||
} view;
|
||||
struct {
|
||||
jclass class;
|
||||
jmethodID dispatchTouchEvent;
|
||||
} view_group;
|
||||
struct {
|
||||
jclass class;
|
||||
jmethodID extractFromAPK;
|
||||
|
|
|
@ -46,11 +46,40 @@ static WrapperWidget *cancel_triggerer = NULL;
|
|||
|
||||
static struct pointer pointers[MAX_POINTERS] = {};
|
||||
|
||||
bool view_dispatch_motionevent(JNIEnv *env, WrapperWidget *wrapper, GtkPropagationPhase phase, jobject motion_event, GdkEvent *event) {
|
||||
int ret;
|
||||
|
||||
jobject this = wrapper->jobj;
|
||||
|
||||
if (wrapper->custom_dispatch_touch) {
|
||||
ret = (*env)->CallBooleanMethod(env, this, handle_cache.view.dispatchTouchEvent, motion_event);
|
||||
} else if (phase == GTK_PHASE_CAPTURE && !wrapper->intercepting_touch) {
|
||||
wrapper->intercepting_touch = (*env)->CallBooleanMethod(env, this, handle_cache.view.onInterceptTouchEvent, motion_event);
|
||||
if (wrapper->intercepting_touch) {
|
||||
if(event) {
|
||||
// store the event that was canceled and let it propagate to the child widgets
|
||||
canceled_event = event;
|
||||
cancel_triggerer = wrapper;
|
||||
} else {
|
||||
/* this function is also called to synthesize an event, in which case there is no GdkEvent so not sure what to do */
|
||||
fprintf(stderr, "view_dispatch_motionevent: onInterceptTouchEvent returned true but this is a synthesized event, please investigate\n");
|
||||
}
|
||||
}
|
||||
ret = false;
|
||||
} else {
|
||||
ret = (*env)->CallBooleanMethod(env, this, handle_cache.view.onTouchEventInternal, motion_event);
|
||||
}
|
||||
|
||||
if((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool call_ontouch_callback(WrapperWidget *wrapper, int action, struct pointer pointers[MAX_POINTERS], GPtrArray *pointer_indices, GtkPropagationPhase phase, guint32 timestamp, GdkEvent *event)
|
||||
{
|
||||
bool ret;
|
||||
JNIEnv *env = get_jni_env();
|
||||
jobject this = wrapper->jobj;
|
||||
|
||||
int num_pointers = pointer_indices->len;
|
||||
jintArray ids = (*env)->NewIntArray(env, num_pointers);
|
||||
|
@ -62,24 +91,9 @@ static bool call_ontouch_callback(WrapperWidget *wrapper, int action, struct poi
|
|||
(*env)->SetFloatArrayRegion(env, coords, 4 * i, 4, &pointer->coord_x);
|
||||
}
|
||||
|
||||
jobject motion_event = (*env)->NewObject(env, handle_cache.motion_event.class, handle_cache.motion_event.constructor, SOURCE_TOUCHSCREEN, action, (long)timestamp, ids, coords);
|
||||
jobject motion_event = (*env)->NewObject(env, handle_cache.motion_event.class, handle_cache.motion_event.constructor, SOURCE_TOUCHSCREEN, action, timestamp, ids, coords);
|
||||
|
||||
if (wrapper->custom_dispatch_touch) {
|
||||
ret = (*env)->CallBooleanMethod(env, this, handle_cache.view.dispatchTouchEvent, motion_event);
|
||||
} else if (phase == GTK_PHASE_CAPTURE && !wrapper->intercepting_touch) {
|
||||
wrapper->intercepting_touch = (*env)->CallBooleanMethod(env, this, handle_cache.view.onInterceptTouchEvent, motion_event);
|
||||
if (wrapper->intercepting_touch) {
|
||||
// store the event that was canceled and let it propagate to the child widgets
|
||||
canceled_event = event;
|
||||
cancel_triggerer = wrapper;
|
||||
}
|
||||
ret = false;
|
||||
} else {
|
||||
ret = (*env)->CallBooleanMethod(env, this, handle_cache.view.onTouchEvent, motion_event);
|
||||
}
|
||||
|
||||
if((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
ret = view_dispatch_motionevent(env, wrapper, phase, motion_event, event);
|
||||
|
||||
(*env)->DeleteLocalRef(env, motion_event);
|
||||
|
||||
|
|
|
@ -63,3 +63,103 @@ JNIEXPORT void JNICALL Java_android_view_ViewGroup_native_1drawChild(JNIEnv *env
|
|||
gtk_widget_queue_draw(child); // FIXME: why didn't compose UI invalidate the child?
|
||||
gtk_widget_snapshot_child(widget, child, snapshot);
|
||||
}
|
||||
|
||||
/* FIXME: put this in a header */
|
||||
G_DECLARE_FINAL_TYPE(JavaWidget, java_widget, JAVA, WIDGET, GtkWidget)
|
||||
bool view_dispatch_motionevent(JNIEnv *env, WrapperWidget *wrapper, GtkPropagationPhase phase, jobject motion_event, GdkEvent *event);
|
||||
|
||||
static bool dispatch_motionevent_if_JavaWidget(GtkWidget *widget, GtkPropagationPhase phase, jobject motion_event)
|
||||
{
|
||||
if(!JAVA_IS_WIDGET(widget))
|
||||
return false;
|
||||
|
||||
return view_dispatch_motionevent(get_jni_env(), WRAPPER_WIDGET(gtk_widget_get_parent(widget)), phase, motion_event, NULL);
|
||||
}
|
||||
|
||||
/* used by atl_propagate_synthetic_motionevent */
|
||||
#define GDK_ARRAY_ELEMENT_TYPE GtkWidget *
|
||||
#define GDK_ARRAY_TYPE_NAME GtkWidgetStack
|
||||
#define GDK_ARRAY_NAME gtk_widget_stack
|
||||
#define GDK_ARRAY_FREE_FUNC g_object_unref
|
||||
#define GDK_ARRAY_PREALLOC 16
|
||||
#include "gdkarrayimpl.c"
|
||||
|
||||
/* based on gtk_propagate_event_internal © GTK Team */
|
||||
bool atl_propagate_synthetic_motionevent(GtkWidget *widget, jobject motionevent, GtkWidget *toplevel)
|
||||
{
|
||||
int handled_event = false;
|
||||
GtkWidgetStack widget_array;
|
||||
int i;
|
||||
|
||||
/* First, propagate event down */
|
||||
gtk_widget_stack_init(&widget_array);
|
||||
gtk_widget_stack_append(&widget_array, g_object_ref(widget));
|
||||
|
||||
for (;;) {
|
||||
widget = gtk_widget_get_parent(widget);
|
||||
if (!widget)
|
||||
break;
|
||||
|
||||
if (widget == toplevel)
|
||||
break;
|
||||
|
||||
gtk_widget_stack_append(&widget_array, g_object_ref(widget));
|
||||
}
|
||||
|
||||
i = gtk_widget_stack_get_size(&widget_array) - 1;
|
||||
for (;;) {
|
||||
widget = gtk_widget_stack_get(&widget_array, i);
|
||||
|
||||
if (!gtk_widget_is_sensitive(widget)) {
|
||||
handled_event = true;
|
||||
} else if (gtk_widget_get_realized(widget))
|
||||
handled_event = dispatch_motionevent_if_JavaWidget(widget, GTK_PHASE_CAPTURE, motionevent);
|
||||
|
||||
handled_event |= !gtk_widget_get_realized(widget);
|
||||
|
||||
if (handled_event)
|
||||
break;
|
||||
|
||||
if (i == 0)
|
||||
break;
|
||||
|
||||
i--;
|
||||
}
|
||||
|
||||
/* If not yet handled, also propagate back up */
|
||||
if (!handled_event) {
|
||||
/* Propagate event up the widget tree so that
|
||||
* parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
for (i = 0; i < gtk_widget_stack_get_size(&widget_array); i++) {
|
||||
widget = gtk_widget_stack_get(&widget_array, i);
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
* to have children of the viewport eat the scroll
|
||||
* event
|
||||
*/
|
||||
if (!gtk_widget_is_sensitive(widget))
|
||||
handled_event = true;
|
||||
else if (gtk_widget_get_realized(widget))
|
||||
handled_event = dispatch_motionevent_if_JavaWidget(widget, GTK_PHASE_BUBBLE, motionevent);
|
||||
|
||||
handled_event |= !gtk_widget_get_realized(widget);
|
||||
|
||||
if (handled_event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_stack_clear(&widget_array);
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_android_view_ViewGroup_native_1dispatchTouchEvent(JNIEnv *env, jobject this, jlong widget_ptr, jobject motion_event, jdouble x, jdouble y)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET(_PTR(widget_ptr));
|
||||
GtkWidget *picked_child = gtk_widget_pick(widget, x, y, GTK_PICK_DEFAULT);
|
||||
|
||||
return atl_propagate_synthetic_motionevent(picked_child, motion_event, widget);
|
||||
}
|
||||
|
|
326
src/api-impl-jni/views/gdkarrayimpl.c
Normal file
326
src/api-impl-jni/views/gdkarrayimpl.c
Normal file
|
@ -0,0 +1,326 @@
|
|||
/* lifted from Gtk for gtk_propagate_event_internal derived function */
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifndef GDK_ARRAY_TYPE_NAME
|
||||
#define GDK_ARRAY_TYPE_NAME GdkArray
|
||||
#endif
|
||||
|
||||
#ifndef GDK_ARRAY_NAME
|
||||
#define GDK_ARRAY_NAME gdk_array
|
||||
#endif
|
||||
|
||||
#ifndef GDK_ARRAY_ELEMENT_TYPE
|
||||
#define GDK_ARRAY_ELEMENT_TYPE gpointer
|
||||
#endif
|
||||
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
#if GDK_ARRAY_PREALLOC == 0
|
||||
#undef GDK_ARRAY_PREALLOC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GDK_ARRAY_NULL_TERMINATED
|
||||
#define GDK_ARRAY_REAL_SIZE(_size) ((_size) + 1)
|
||||
#define GDK_ARRAY_MAX_SIZE (G_MAXSIZE / sizeof(_T_) - 1)
|
||||
#else
|
||||
#define GDK_ARRAY_REAL_SIZE(_size) (_size)
|
||||
#define GDK_ARRAY_MAX_SIZE (G_MAXSIZE / sizeof(_T_))
|
||||
#endif
|
||||
|
||||
/* make this readable */
|
||||
#define _T_ GDK_ARRAY_ELEMENT_TYPE
|
||||
#define GdkArray GDK_ARRAY_TYPE_NAME
|
||||
#define gdk_array_paste_more(GDK_ARRAY_NAME, func_name) GDK_ARRAY_NAME##_##func_name
|
||||
#define gdk_array_paste(GDK_ARRAY_NAME, func_name) gdk_array_paste_more(GDK_ARRAY_NAME, func_name)
|
||||
#define gdk_array(func_name) gdk_array_paste(GDK_ARRAY_NAME, func_name)
|
||||
|
||||
typedef struct GdkArray GdkArray;
|
||||
|
||||
struct GdkArray {
|
||||
_T_ *start;
|
||||
_T_ *end;
|
||||
_T_ *end_allocation;
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
_T_ preallocated[GDK_ARRAY_REAL_SIZE(GDK_ARRAY_PREALLOC)];
|
||||
#endif
|
||||
};
|
||||
|
||||
/* no G_GNUC_UNUSED here, if you don't use an array type, remove it. */
|
||||
static inline void
|
||||
gdk_array(init)(GdkArray *self)
|
||||
{
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
self->start = self->preallocated;
|
||||
self->end = self->start;
|
||||
self->end_allocation = self->start + GDK_ARRAY_PREALLOC;
|
||||
#ifdef GDK_ARRAY_NULL_TERMINATED
|
||||
*self->start = *(_T_[1]){0};
|
||||
#endif
|
||||
#else
|
||||
self->start = NULL;
|
||||
self->end = NULL;
|
||||
self->end_allocation = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gdk_array(get_capacity)(const GdkArray *self)
|
||||
{
|
||||
return self->end_allocation - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gdk_array(get_size)(const GdkArray *self)
|
||||
{
|
||||
return self->end - self->start;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_array(free_elements)(_T_ *start,
|
||||
_T_ *end)
|
||||
{
|
||||
#ifdef GDK_ARRAY_FREE_FUNC
|
||||
_T_ *e;
|
||||
for (e = start; e < end; e++)
|
||||
#ifdef GDK_ARRAY_BY_VALUE
|
||||
GDK_ARRAY_FREE_FUNC(e);
|
||||
#else
|
||||
GDK_ARRAY_FREE_FUNC(*e);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* no G_GNUC_UNUSED here */
|
||||
static inline void
|
||||
gdk_array(clear)(GdkArray *self)
|
||||
{
|
||||
gdk_array(free_elements)(self->start, self->end);
|
||||
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
if (self->start != self->preallocated)
|
||||
#endif
|
||||
g_free(self->start);
|
||||
gdk_array(init)(self);
|
||||
}
|
||||
|
||||
/*
|
||||
* gdk_array_steal:
|
||||
* @self: the array
|
||||
*
|
||||
* Steals all data in the array and clears the array.
|
||||
*
|
||||
* If you need to know the size of the data, you should query it
|
||||
* beforehand.
|
||||
*
|
||||
* Returns: The array's data
|
||||
**/
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gdk_array(steal)(GdkArray *self)
|
||||
{
|
||||
_T_ *result;
|
||||
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
if (self->start == self->preallocated) {
|
||||
gsize size = GDK_ARRAY_REAL_SIZE(gdk_array(get_size)(self));
|
||||
result = g_new(_T_, size);
|
||||
memcpy(result, self->preallocated, sizeof(_T_) * size);
|
||||
} else
|
||||
#endif
|
||||
result = self->start;
|
||||
|
||||
gdk_array(init)(self);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gdk_array(get_data)(const GdkArray *self)
|
||||
{
|
||||
return self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gdk_array(index)(const GdkArray *self,
|
||||
gsize pos)
|
||||
{
|
||||
return self->start + pos;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gboolean
|
||||
gdk_array(is_empty)(const GdkArray *self)
|
||||
{
|
||||
return self->end == self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline void
|
||||
gdk_array(reserve)(GdkArray *self,
|
||||
gsize n)
|
||||
{
|
||||
gsize new_capacity, size, capacity;
|
||||
|
||||
if (G_UNLIKELY(n > GDK_ARRAY_MAX_SIZE))
|
||||
g_error("requesting array size of %zu, but maximum size is %zu", n, GDK_ARRAY_MAX_SIZE);
|
||||
|
||||
capacity = gdk_array(get_capacity)(self);
|
||||
if (n <= capacity)
|
||||
return;
|
||||
|
||||
size = gdk_array(get_size)(self);
|
||||
/* capacity * 2 can overflow, that's why we MAX() */
|
||||
new_capacity = MAX(GDK_ARRAY_REAL_SIZE(n), capacity * 2);
|
||||
|
||||
#ifdef GDK_ARRAY_PREALLOC
|
||||
if (self->start == self->preallocated) {
|
||||
self->start = g_new(_T_, new_capacity);
|
||||
memcpy(self->start, self->preallocated, sizeof(_T_) * GDK_ARRAY_REAL_SIZE(size));
|
||||
} else
|
||||
#endif
|
||||
#ifdef GDK_ARRAY_NULL_TERMINATED
|
||||
if (self->start == NULL) {
|
||||
self->start = g_new(_T_, new_capacity);
|
||||
*self->start = *(_T_[1]){0};
|
||||
} else
|
||||
#endif
|
||||
self->start = g_renew(_T_, self->start, new_capacity);
|
||||
|
||||
self->end = self->start + size;
|
||||
self->end_allocation = self->start + new_capacity;
|
||||
#ifdef GDK_ARRAY_NULL_TERMINATED
|
||||
self->end_allocation--;
|
||||
#endif
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline void
|
||||
gdk_array(splice)(GdkArray *self,
|
||||
gsize pos,
|
||||
gsize removed,
|
||||
gboolean stolen,
|
||||
#ifdef GDK_ARRAY_BY_VALUE
|
||||
const _T_ *additions,
|
||||
#else
|
||||
_T_ *additions,
|
||||
#endif
|
||||
gsize added)
|
||||
{
|
||||
gsize size;
|
||||
gsize remaining;
|
||||
|
||||
size = gdk_array(get_size)(self);
|
||||
g_assert(pos + removed <= size);
|
||||
remaining = size - pos - removed;
|
||||
|
||||
if (!stolen)
|
||||
gdk_array(free_elements)(gdk_array(index)(self, pos),
|
||||
gdk_array(index)(self, pos + removed));
|
||||
|
||||
gdk_array(reserve)(self, size - removed + added);
|
||||
|
||||
if (GDK_ARRAY_REAL_SIZE(remaining) && removed != added)
|
||||
memmove(gdk_array(index)(self, pos + added),
|
||||
gdk_array(index)(self, pos + removed),
|
||||
GDK_ARRAY_REAL_SIZE(remaining) * sizeof(_T_));
|
||||
|
||||
if (added) {
|
||||
if (additions)
|
||||
memcpy(gdk_array(index)(self, pos),
|
||||
additions,
|
||||
added * sizeof(_T_));
|
||||
#ifndef GDK_ARRAY_NO_MEMSET
|
||||
else
|
||||
memset(gdk_array(index)(self, pos), 0, added * sizeof(_T_));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* might overflow, but does the right thing */
|
||||
self->end += added - removed;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gdk_array(set_size)(GdkArray *self,
|
||||
gsize new_size)
|
||||
{
|
||||
gsize old_size = gdk_array(get_size)(self);
|
||||
if (new_size > old_size)
|
||||
gdk_array(splice)(self, old_size, 0, FALSE, NULL, new_size - old_size);
|
||||
else
|
||||
gdk_array(splice)(self, new_size, old_size - new_size, FALSE, NULL, 0);
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gdk_array(append)(GdkArray *self,
|
||||
#ifdef GDK_ARRAY_BY_VALUE
|
||||
_T_ *value)
|
||||
#else
|
||||
_T_ value)
|
||||
#endif
|
||||
{
|
||||
gdk_array(splice)(self,
|
||||
gdk_array(get_size)(self),
|
||||
0,
|
||||
FALSE,
|
||||
#ifdef GDK_ARRAY_BY_VALUE
|
||||
value,
|
||||
#else
|
||||
&value,
|
||||
#endif
|
||||
1);
|
||||
}
|
||||
|
||||
#ifdef GDK_ARRAY_BY_VALUE
|
||||
G_GNUC_UNUSED static _T_ *
|
||||
gdk_array(get)(const GdkArray *self,
|
||||
gsize pos)
|
||||
{
|
||||
return gdk_array(index)(self, pos);
|
||||
}
|
||||
#else
|
||||
G_GNUC_UNUSED static _T_
|
||||
gdk_array(get)(const GdkArray *self,
|
||||
gsize pos)
|
||||
{
|
||||
return *gdk_array(index)(self, pos);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef GDK_ARRAY_NO_UNDEF
|
||||
|
||||
#undef _T_
|
||||
#undef GdkArray
|
||||
#undef gdk_array_paste_more
|
||||
#undef gdk_array_paste
|
||||
#undef gdk_array
|
||||
#undef GDK_ARRAY_REAL_SIZE
|
||||
#undef GDK_ARRAY_MAX_SIZE
|
||||
|
||||
#undef GDK_ARRAY_BY_VALUE
|
||||
#undef GDK_ARRAY_ELEMENT_TYPE
|
||||
#undef GDK_ARRAY_FREE_FUNC
|
||||
#undef GDK_ARRAY_NAME
|
||||
#undef GDK_ARRAY_NULL_TERMINATED
|
||||
#undef GDK_ARRAY_PREALLOC
|
||||
#undef GDK_ARRAY_TYPE_NAME
|
||||
#undef GDK_ARRAY_NO_MEMSET
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
|
@ -386,7 +386,7 @@ void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject job
|
|||
|
||||
jmethodID ontouchevent_method = _METHOD(_CLASS(jobj), "onTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||
jmethodID dispatchtouchevent_method = _METHOD(_CLASS(jobj), "dispatchTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||
wrapper->custom_dispatch_touch = dispatchtouchevent_method != handle_cache.view.dispatchTouchEvent;
|
||||
wrapper->custom_dispatch_touch = (dispatchtouchevent_method != handle_cache.view.dispatchTouchEvent && dispatchtouchevent_method != handle_cache.view_group.dispatchTouchEvent);
|
||||
if (ontouchevent_method != handle_cache.view.onTouchEvent || wrapper->custom_dispatch_touch) {
|
||||
_setOnTouchListener(env, jobj, GTK_WIDGET(wrapper));
|
||||
}
|
||||
|
|
|
@ -1075,13 +1075,22 @@ public class View implements Drawable.Callback {
|
|||
}
|
||||
|
||||
private OnTouchListener on_touch_listener = null;
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
|
||||
public boolean onTouchEventInternal(MotionEvent event) {
|
||||
boolean handled = false;
|
||||
if (on_touch_listener != null)
|
||||
handled = on_touch_listener.onTouch(this, event);
|
||||
|
||||
if (!handled)
|
||||
handled = onTouchEvent(event);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setOnTouchListener(OnTouchListener l) {
|
||||
nativeSetOnTouchListener(widget);
|
||||
on_touch_listener = l;
|
||||
|
@ -1206,12 +1215,21 @@ public class View implements Drawable.Callback {
|
|||
|
||||
public native void setBackgroundColor(int color);
|
||||
public native void native_setVisibility(long widget, int visibility, float alpha);
|
||||
|
||||
protected void onVisibilityChanged(View changedView, int visibility) {
|
||||
}
|
||||
|
||||
protected void dispatchVisibilityChanged(View changedView, int visibility) {
|
||||
onVisibilityChanged(changedView, visibility);
|
||||
}
|
||||
|
||||
public void setVisibility(int visibility) {
|
||||
native_setVisibility(widget, visibility, alpha);
|
||||
if ((visibility == View.GONE) != (this.visibility == View.GONE)) {
|
||||
requestLayout();
|
||||
}
|
||||
this.visibility = visibility;
|
||||
dispatchVisibilityChanged(this, visibility);
|
||||
}
|
||||
|
||||
public void setPadding(int left, int top, int right, int bottom) {
|
||||
|
|
|
@ -61,6 +61,10 @@ public class ViewGroup extends View implements ViewParent, ViewManager {
|
|||
addView(child, params);
|
||||
}
|
||||
|
||||
public void addView(View child, int index, LayoutParams params) {
|
||||
addViewInternal(child, index, params);
|
||||
}
|
||||
|
||||
protected void addViewInternal(View child, int index, LayoutParams params) {
|
||||
if (child.parent == this)
|
||||
return;
|
||||
|
@ -81,10 +85,13 @@ public class ViewGroup extends View implements ViewParent, ViewManager {
|
|||
requestLayout();
|
||||
}
|
||||
|
||||
public void addView(View child, int index, LayoutParams params) {
|
||||
addViewInternal(child, index, params);
|
||||
/* We never call this ourselves */
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
return native_dispatchTouchEvent(widget, event, event.getX(), event.getY());
|
||||
}
|
||||
|
||||
|
||||
protected boolean addViewInLayout(View child, int index, LayoutParams params) {
|
||||
addViewInternal(child, index, params);
|
||||
return true;
|
||||
|
@ -169,6 +176,16 @@ public class ViewGroup extends View implements ViewParent, ViewManager {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchVisibilityChanged(View changedView, int visibility) {
|
||||
if (children == null) // happens if this gets called during super constructor
|
||||
return;
|
||||
|
||||
for (View child: children) {
|
||||
child.dispatchVisibilityChanged(changedView, visibility);
|
||||
}
|
||||
}
|
||||
|
||||
protected native void native_addView(long widget, long child, int index, LayoutParams params);
|
||||
protected native void native_removeView(long widget, long child);
|
||||
@Override
|
||||
|
@ -636,4 +653,6 @@ public class ViewGroup extends View implements ViewParent, ViewManager {
|
|||
}
|
||||
|
||||
public void requestChildFocus(View child, View focused) {}
|
||||
|
||||
public native boolean native_dispatchTouchEvent(long widget, MotionEvent event, double x, double y);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue