2022-10-02 23:06:56 +02:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
2023-07-14 17:53:12 +02:00
|
|
|
#include "../defines.h"
|
|
|
|
|
#include "../util.h"
|
2022-10-02 23:06:56 +02:00
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
#include "../sk_area/sk_area.h"
|
2022-10-02 23:06:56 +02:00
|
|
|
|
2023-10-17 21:33:59 +02:00
|
|
|
#include "../generated_headers/android_view_View.h"
|
|
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
#include "WrapperWidget.h"
|
2022-10-02 23:06:56 +02:00
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(WrapperWidget, wrapper_widget, GTK_TYPE_WIDGET)
|
|
|
|
|
|
2022-11-02 14:37:34 +01:00
|
|
|
static void wrapper_widget_init (WrapperWidget *wrapper_widget)
|
2022-10-02 23:06:56 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void wrapper_widget_dispose(GObject *wrapper_widget)
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_unparent(gtk_widget_get_first_child(GTK_WIDGET(wrapper_widget)));
|
2023-07-14 17:53:12 +02:00
|
|
|
WrapperWidget *wrapper = WRAPPER_WIDGET(wrapper_widget);
|
|
|
|
|
if (wrapper->jvm) {
|
|
|
|
|
JNIEnv *env;
|
|
|
|
|
(*wrapper->jvm)->GetEnv(wrapper->jvm, (void**)&env, JNI_VERSION_1_6);
|
|
|
|
|
if (wrapper->jobj)
|
|
|
|
|
_UNREF(wrapper->jobj);
|
|
|
|
|
if (wrapper->canvas)
|
|
|
|
|
_UNREF(wrapper->canvas);
|
|
|
|
|
}
|
2022-10-02 23:06:56 +02:00
|
|
|
G_OBJECT_CLASS (wrapper_widget_parent_class)->dispose (wrapper_widget);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
void skia_draw_func(SKArea *sk_area, sk_canvas_t *canvas, WrapperWidget *wrapper_widget)
|
2022-10-02 23:06:56 +02:00
|
|
|
{
|
2023-08-28 20:03:32 +02:00
|
|
|
JNIEnv *env;
|
|
|
|
|
(*wrapper_widget->jvm)->GetEnv(wrapper_widget->jvm, (void**)&env, JNI_VERSION_1_6);
|
|
|
|
|
if(wrapper_widget->canvas == NULL) {
|
|
|
|
|
wrapper_widget->canvas = _REF((*env)->NewObject(env, handle_cache.canvas.class, handle_cache.canvas.constructor, _INTPTR(canvas), 0));
|
|
|
|
|
} else {
|
|
|
|
|
_SET_LONG_FIELD(wrapper_widget->canvas, "skia_canvas", _INTPTR(canvas));
|
2022-10-02 23:06:56 +02:00
|
|
|
}
|
2023-07-14 17:53:12 +02:00
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
(*env)->CallVoidMethod(env, wrapper_widget->jobj, wrapper_widget->draw_method, wrapper_widget->canvas);
|
2023-07-14 17:53:12 +02:00
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
if((*env)->ExceptionCheck(env))
|
|
|
|
|
(*env)->ExceptionDescribe(env);
|
2022-10-02 23:06:56 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
/*void wrapper_snapshot(GtkWidget* widget, GtkSnapshot* snapshot)
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_snapshot_child(widget, gtk_widget_get_first_child(widget), snapshot);
|
|
|
|
|
}*/
|
|
|
|
|
|
2022-10-02 23:06:56 +02:00
|
|
|
|
|
|
|
|
static void wrapper_widget_class_init(WrapperWidgetClass *class)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
|
|
|
|
|
|
|
|
|
object_class->dispose = wrapper_widget_dispose;
|
|
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
// widget_class->snapshot = wrapper_snapshot;
|
2022-10-02 23:06:56 +02:00
|
|
|
|
|
|
|
|
gtk_widget_class_set_layout_manager_type(widget_class, GTK_TYPE_BIN_LAYOUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GtkWidget * wrapper_widget_new(void)
|
|
|
|
|
{
|
|
|
|
|
return g_object_new (wrapper_widget_get_type(), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child) // TODO: make sure there can only be one child
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_insert_before(child, GTK_WIDGET(parent), NULL);
|
|
|
|
|
}
|
2023-07-14 17:53:12 +02:00
|
|
|
|
2023-08-17 10:46:24 +02:00
|
|
|
#define MEASURE_SPEC_EXACTLY (1 << 30)
|
|
|
|
|
|
2023-07-14 17:53:12 +02:00
|
|
|
static void on_mapped(GtkWidget* self, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
WrapperWidget *wrapper = WRAPPER_WIDGET(self);
|
|
|
|
|
if (wrapper->jvm) {
|
|
|
|
|
JNIEnv *env;
|
|
|
|
|
(*wrapper->jvm)->GetEnv(wrapper->jvm, (void**)&env, JNI_VERSION_1_6);
|
|
|
|
|
|
2023-08-22 14:18:33 +02:00
|
|
|
(*env)->CallVoidMethod(env, wrapper->jobj, wrapper->measure_method, MEASURE_SPEC_EXACTLY | gtk_widget_get_width(self), MEASURE_SPEC_EXACTLY | gtk_widget_get_height(self));
|
|
|
|
|
int width = (*env)->CallIntMethod(env, wrapper->jobj, handle_cache.view.getMeasuredWidth);
|
|
|
|
|
if (width > 0)
|
|
|
|
|
g_object_set(G_OBJECT(self), "width-request", width, NULL);
|
|
|
|
|
int height = (*env)->CallIntMethod(env, wrapper->jobj, handle_cache.view.getMeasuredHeight);
|
|
|
|
|
if (height > 0)
|
|
|
|
|
g_object_set(G_OBJECT(self), "height-request", height, NULL);
|
2023-07-14 17:53:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
// FIXME: this is used in one other place as well, should probably go in util.c or gtk_util.c?
|
|
|
|
|
gboolean tick_callback(GtkWidget* widget, GdkFrameClock* frame_clock, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_queue_draw(widget);
|
|
|
|
|
gtk_widget_queue_draw(gtk_widget_get_parent(widget));
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-14 17:53:12 +02:00
|
|
|
void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject jobj)
|
|
|
|
|
{
|
|
|
|
|
JavaVM *jvm;
|
|
|
|
|
(*env)->GetJavaVM(env, &jvm);
|
|
|
|
|
wrapper->jvm = jvm;
|
|
|
|
|
wrapper->jobj = _REF(jobj);
|
|
|
|
|
jmethodID draw_method = _METHOD(_CLASS(jobj), "onDraw", "(Landroid/graphics/Canvas;)V");
|
2023-08-28 20:03:32 +02:00
|
|
|
if (draw_method != handle_cache.view.onDraw) {
|
2023-07-14 17:53:12 +02:00
|
|
|
wrapper->draw_method = draw_method;
|
|
|
|
|
|
2023-08-28 20:03:32 +02:00
|
|
|
GtkWidget *sk_area = sk_area_new();
|
|
|
|
|
sk_area_set_draw_func(SK_AREA_WIDGET(sk_area), skia_draw_func, wrapper);
|
|
|
|
|
gtk_widget_insert_before(sk_area, GTK_WIDGET(wrapper), NULL);
|
|
|
|
|
gtk_widget_add_tick_callback(sk_area, tick_callback, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-14 17:53:12 +02:00
|
|
|
jmethodID measure_method = _METHOD(_CLASS(jobj), "onMeasure", "(II)V");
|
|
|
|
|
if (measure_method != handle_cache.view.onMeasure) {
|
|
|
|
|
wrapper->measure_method = measure_method;
|
|
|
|
|
// add a callback for when the widget is mapped, which will call onMeasure to figure out what size the widget wants to be
|
|
|
|
|
g_signal_connect(wrapper, "map", G_CALLBACK(on_mapped), NULL);
|
|
|
|
|
}
|
2023-10-17 21:33:59 +02:00
|
|
|
|
|
|
|
|
jmethodID ontouchevent_method = _METHOD(_CLASS(jobj), "onTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
|
|
|
|
if (ontouchevent_method != handle_cache.view.onTouchEvent) {
|
|
|
|
|
/* use gtk_widget_get_first_child since the jobject may not have the "widget" variable set yet */
|
|
|
|
|
_setOnTouchListener(env, jobj, gtk_widget_get_first_child(wrapper), NULL);
|
|
|
|
|
}
|
2023-07-14 17:53:12 +02:00
|
|
|
}
|