2022-10-02 23:06:56 +02:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
#include "../defines.h"
|
|
|
|
|
#include "../util.h"
|
|
|
|
|
|
2023-08-17 12:59:37 +02:00
|
|
|
#include "../widgets/WrapperWidget.h"
|
2023-10-31 22:37:11 +01:00
|
|
|
#include "../views/AndroidLayout.h"
|
2023-08-17 12:59:37 +02:00
|
|
|
|
2022-10-02 23:06:56 +02:00
|
|
|
#include "../generated_headers/android_view_ViewGroup.h"
|
|
|
|
|
#include "../generated_headers/android_view_View.h"
|
|
|
|
|
|
2023-08-17 12:59:37 +02:00
|
|
|
JNIEXPORT void JNICALL Java_android_view_ViewGroup_native_1addView(JNIEnv *env, jobject this, jlong widget, jlong child, jint index, jobject layout_params)
|
|
|
|
|
{
|
2022-10-02 23:06:56 +02:00
|
|
|
if(layout_params) {
|
|
|
|
|
/*
|
2023-08-17 12:59:37 +02:00
|
|
|
GtkWidget *_child = gtk_widget_get_parent(GTK_WIDGET(_PTR(child)));
|
|
|
|
|
jint child_width = -1;
|
|
|
|
|
jint child_height = -1;
|
|
|
|
|
|
2022-10-02 23:06:56 +02:00
|
|
|
jint child_width = _GET_INT_FIELD(layout_params, "width");
|
|
|
|
|
jint child_height = _GET_INT_FIELD(layout_params, "height");
|
|
|
|
|
|
|
|
|
|
jint child_gravity = _GET_INT_FIELD(layout_params, "gravity");
|
|
|
|
|
|
|
|
|
|
if(child_width > 0)
|
|
|
|
|
g_object_set(G_OBJECT(_child), "width-request", child_width, NULL);
|
|
|
|
|
if(child_height > 0)
|
|
|
|
|
g_object_set(G_OBJECT(_child), "height-request", child_height, NULL);
|
|
|
|
|
|
|
|
|
|
if(child_gravity != -1) {
|
|
|
|
|
printf(":::-: setting child gravity: %d", child_gravity);
|
|
|
|
|
Java_android_view_View_setGravity(env, child, child_gravity);
|
|
|
|
|
}*/
|
|
|
|
|
}
|
2023-09-01 13:49:42 +02:00
|
|
|
GtkWidget *parent = _PTR(widget);
|
|
|
|
|
GtkWidget *iter = gtk_widget_get_first_child(parent);
|
|
|
|
|
for(int i = 0; i < index; i++) {
|
|
|
|
|
iter = gtk_widget_get_next_sibling(iter);
|
|
|
|
|
if(iter == NULL)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtk_widget_insert_before(gtk_widget_get_parent(GTK_WIDGET(_PTR(child))), parent, iter);
|
2022-10-02 23:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-17 12:59:37 +02:00
|
|
|
JNIEXPORT void JNICALL Java_android_view_ViewGroup_native_1removeView(JNIEnv *env, jobject this, jlong widget, jlong child)
|
2022-10-02 23:06:56 +02:00
|
|
|
{
|
2023-09-01 13:49:42 +02:00
|
|
|
gtk_widget_unparent(gtk_widget_get_parent(GTK_WIDGET(_PTR(child))));
|
2022-10-02 23:06:56 +02:00
|
|
|
}
|
2024-05-26 15:53:24 +02:00
|
|
|
|
|
|
|
|
JNIEXPORT void JNICALL Java_android_view_ViewGroup_native_1drawChildren(JNIEnv *env, jobject this, jlong widget_ptr, jlong snapshot_ptr)
|
|
|
|
|
{
|
|
|
|
|
WrapperWidget *wrapper = WRAPPER_WIDGET(gtk_widget_get_parent(GTK_WIDGET(_PTR(widget_ptr))));
|
|
|
|
|
GdkSnapshot *snapshot = GDK_SNAPSHOT(_PTR(snapshot_ptr));
|
|
|
|
|
gtk_widget_snapshot_child(&wrapper->parent_instance, wrapper->child, snapshot);
|
|
|
|
|
}
|
2024-11-30 17:58:31 +01:00
|
|
|
|
|
|
|
|
JNIEXPORT void JNICALL Java_android_view_ViewGroup_native_1drawChild(JNIEnv *env, jobject this, jlong widget_ptr, jlong child_ptr, jlong snapshot_ptr)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *widget = GTK_WIDGET(_PTR(widget_ptr));
|
|
|
|
|
GtkWidget *child = gtk_widget_get_parent(GTK_WIDGET(_PTR(child_ptr)));
|
|
|
|
|
GdkSnapshot *snapshot = GDK_SNAPSHOT(_PTR(snapshot_ptr));
|
|
|
|
|
gtk_widget_queue_draw(child); // FIXME: why didn't compose UI invalidate the child?
|
|
|
|
|
gtk_widget_snapshot_child(widget, child, snapshot);
|
|
|
|
|
}
|
2025-03-26 20:06:09 +01:00
|
|
|
|
|
|
|
|
/* FIXME: put this in a header */
|
|
|
|
|
G_DECLARE_FINAL_TYPE(JavaWidget, java_widget, JAVA, WIDGET, GtkWidget)
|
2025-04-19 15:32:27 +02:00
|
|
|
bool view_dispatch_motionevent(JNIEnv *env, WrapperWidget *wrapper, GtkPropagationPhase phase, jobject motion_event, gpointer event, int action);
|
2025-03-26 20:06:09 +01:00
|
|
|
|
|
|
|
|
static bool dispatch_motionevent_if_JavaWidget(GtkWidget *widget, GtkPropagationPhase phase, jobject motion_event)
|
|
|
|
|
{
|
|
|
|
|
if(!JAVA_IS_WIDGET(widget))
|
|
|
|
|
return false;
|
2025-04-19 15:32:27 +02:00
|
|
|
JNIEnv *env = get_jni_env();
|
2025-03-26 20:06:09 +01:00
|
|
|
|
2025-04-19 15:32:27 +02:00
|
|
|
WrapperWidget *wrapper = WRAPPER_WIDGET(gtk_widget_get_parent(widget));
|
|
|
|
|
int action = _GET_INT_FIELD(motion_event, "action");
|
|
|
|
|
return view_dispatch_motionevent(env, wrapper, phase, motion_event, motion_event, action);
|
2025-03-26 20:06:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|