You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
handle overwritten onDraw function in WrapperWidget
This makes it easy to support for example ImageView with custom onDraw function
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
#define _PTR(ptr)((void*)(intptr_t)(ptr))
|
#define _PTR(ptr)((void*)(intptr_t)(ptr))
|
||||||
#define _INTPTR(ptr)((jlong)(intptr_t)(ptr))
|
#define _INTPTR(ptr)((jlong)(intptr_t)(ptr))
|
||||||
#define _REF(obj)((*env)->NewGlobalRef(env, obj))
|
#define _REF(obj)((*env)->NewGlobalRef(env, obj))
|
||||||
|
#define _UNREF(obj)((*env)->DeleteGlobalRef(env, obj))
|
||||||
#define _CLASS(object) ((*env)->GetObjectClass(env, object))
|
#define _CLASS(object) ((*env)->GetObjectClass(env, object))
|
||||||
#define _SUPER(object) ((*env)->GetSuperclass(env, object))
|
#define _SUPER(object) ((*env)->GetSuperclass(env, object))
|
||||||
#define _METHOD(class, method, attrs) ((*env)->GetMethodID(env, class, method, attrs))
|
#define _METHOD(class, method, attrs) ((*env)->GetMethodID(env, class, method, attrs))
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ void set_up_handle_cache(JNIEnv *env, char *apk_main_activity_class)
|
|||||||
handle_cache.view.setLayoutParams = _METHOD(handle_cache.view.class, "setLayoutParams", "(Landroid/view/ViewGroup$LayoutParams;)V");
|
handle_cache.view.setLayoutParams = _METHOD(handle_cache.view.class, "setLayoutParams", "(Landroid/view/ViewGroup$LayoutParams;)V");
|
||||||
if((*env)->ExceptionCheck(env))
|
if((*env)->ExceptionCheck(env))
|
||||||
(*env)->ExceptionDescribe(env);
|
(*env)->ExceptionDescribe(env);
|
||||||
|
handle_cache.view.onDraw = _METHOD(handle_cache.view.class, "onDraw", "(Landroid/graphics/Canvas;)V");
|
||||||
|
handle_cache.view.onMeasure = _METHOD(handle_cache.view.class, "onMeasure", "(II)V");
|
||||||
|
|
||||||
handle_cache.asset_manager.class = _REF((*env)->FindClass(env, "android/content/res/AssetManager"));
|
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");
|
handle_cache.asset_manager.extractFromAPK = _STATIC_METHOD(handle_cache.asset_manager.class, "extractFromAPK", "(Ljava/lang/String;Ljava/lang/String;)V");
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ struct handle_cache {
|
|||||||
struct {
|
struct {
|
||||||
jclass class;
|
jclass class;
|
||||||
jmethodID setLayoutParams;
|
jmethodID setLayoutParams;
|
||||||
|
jmethodID onDraw;
|
||||||
|
jmethodID onMeasure;
|
||||||
} view;
|
} view;
|
||||||
struct {
|
struct {
|
||||||
jclass class;
|
jclass class;
|
||||||
|
|||||||
@@ -166,43 +166,11 @@ JNIEXPORT void JNICALL Java_android_view_View_setVisibility(JNIEnv *env, jobject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- the stuff below only applies to widgets that override the OnDraw() method; other widgets are created by class-specific constructors.
|
|
||||||
// FIXME: how do we handle someone subclassing something other then View and then overriding the onDraw/onMeasure method(s)?
|
|
||||||
|
|
||||||
struct jni_callback_data { JavaVM *jvm; jobject this; jclass this_class; cairo_t *cached_cr; jobject canvas;};
|
|
||||||
|
|
||||||
static void draw_function(GtkDrawingArea *area, cairo_t *cr, int width, int height, struct jni_callback_data *d)
|
|
||||||
{
|
|
||||||
JNIEnv *env;
|
|
||||||
(*d->jvm)->GetEnv(d->jvm, (void**)&env, JNI_VERSION_1_6);
|
|
||||||
|
|
||||||
if(d->cached_cr != cr) {
|
|
||||||
if(d->canvas == NULL) {
|
|
||||||
d->canvas = _REF((*env)->NewObject(env, handle_cache.canvas.class, handle_cache.canvas.constructor, _INTPTR(cr), _INTPTR(area)));
|
|
||||||
} else {
|
|
||||||
_SET_LONG_FIELD(d->canvas, "cairo_context", _INTPTR(cr));
|
|
||||||
}
|
|
||||||
d->cached_cr = cr;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, d->this, _METHOD(d->this_class, "onDraw", "(Landroid/graphics/Canvas;)V"), d->canvas);
|
|
||||||
|
|
||||||
if((*env)->ExceptionCheck(env))
|
|
||||||
(*env)->ExceptionDescribe(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void on_mapped(GtkWidget* self, struct jni_callback_data *d)
|
|
||||||
{
|
|
||||||
JNIEnv *env;
|
|
||||||
(*d->jvm)->GetEnv(d->jvm, (void**)&env, JNI_VERSION_1_6);
|
|
||||||
|
|
||||||
(*env)->CallVoidMethod(env, d->this, _METHOD(d->this_class, "onMeasure", "(II)V"), gtk_widget_get_width(self), gtk_widget_get_height(self));
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: this is used in one other place as well, should probably go in util.c or gtk_util.c?
|
// 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)
|
gboolean tick_callback(GtkWidget* widget, GdkFrameClock* frame_clock, gpointer user_data)
|
||||||
{
|
{
|
||||||
gtk_widget_queue_draw(widget);
|
gtk_widget_queue_draw(widget);
|
||||||
|
gtk_widget_queue_draw(gtk_widget_get_parent(widget));
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,24 +179,10 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1constructor(JNIEnv *env, j
|
|||||||
GtkWidget *wrapper = wrapper_widget_new();
|
GtkWidget *wrapper = wrapper_widget_new();
|
||||||
GtkWidget *area = gtk_drawing_area_new();
|
GtkWidget *area = gtk_drawing_area_new();
|
||||||
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), area);
|
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), area);
|
||||||
|
wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this);
|
||||||
JavaVM *jvm;
|
|
||||||
(*env)->GetJavaVM(env, &jvm);
|
|
||||||
|
|
||||||
struct jni_callback_data *callback_data = malloc(sizeof(struct jni_callback_data));
|
|
||||||
callback_data->jvm = jvm;
|
|
||||||
callback_data->this = _REF(this);
|
|
||||||
callback_data->this_class = _REF(_CLASS(this));
|
|
||||||
callback_data->cached_cr = NULL;
|
|
||||||
callback_data->canvas = NULL;
|
|
||||||
|
|
||||||
gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(area), ( void(*)(GtkDrawingArea*,cairo_t*,int,int,gpointer) )draw_function, callback_data, NULL);
|
|
||||||
|
|
||||||
gtk_widget_add_tick_callback(area, tick_callback, NULL, NULL);
|
gtk_widget_add_tick_callback(area, tick_callback, NULL, NULL);
|
||||||
|
|
||||||
// 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(area, "map", G_CALLBACK(on_mapped), callback_data);
|
|
||||||
|
|
||||||
_SET_LONG_FIELD(this, "widget", (long)area);
|
_SET_LONG_FIELD(this, "widget", (long)area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "../defines.h"
|
||||||
|
#include "../util.h"
|
||||||
#include "../drawables/ninepatch.h"
|
#include "../drawables/ninepatch.h"
|
||||||
|
|
||||||
#include "WrapperWidget.h"
|
#include "WrapperWidget.h"
|
||||||
@@ -52,6 +54,15 @@ static void wrapper_widget_init (WrapperWidget *wrapper_widget)
|
|||||||
static void wrapper_widget_dispose(GObject *wrapper_widget)
|
static void wrapper_widget_dispose(GObject *wrapper_widget)
|
||||||
{
|
{
|
||||||
gtk_widget_unparent(gtk_widget_get_first_child(GTK_WIDGET(wrapper_widget)));
|
gtk_widget_unparent(gtk_widget_get_first_child(GTK_WIDGET(wrapper_widget)));
|
||||||
|
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);
|
||||||
|
}
|
||||||
G_OBJECT_CLASS (wrapper_widget_parent_class)->dispose (wrapper_widget);
|
G_OBJECT_CLASS (wrapper_widget_parent_class)->dispose (wrapper_widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +89,29 @@ void wrapper_snapshot(GtkWidget* widget, GtkSnapshot* snapshot)
|
|||||||
g_object_unref(texture);
|
g_object_unref(texture);
|
||||||
}
|
}
|
||||||
gtk_widget_snapshot_child(widget, gtk_widget_get_first_child(widget), snapshot);
|
gtk_widget_snapshot_child(widget, gtk_widget_get_first_child(widget), snapshot);
|
||||||
|
|
||||||
|
// if onDraw method is overwritten call it now
|
||||||
|
WrapperWidget *wrapper_widget = WRAPPER_WIDGET(widget);
|
||||||
|
GtkAllocation alloc;
|
||||||
|
gtk_widget_get_allocation(widget, &alloc);
|
||||||
|
if (wrapper_widget->draw_method) {
|
||||||
|
cairo_t *cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT(0, 0, alloc.width, alloc.height));
|
||||||
|
|
||||||
|
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(cr), 0));
|
||||||
|
} else {
|
||||||
|
_SET_LONG_FIELD(wrapper_widget->canvas, "cairo_context", _INTPTR(cr));
|
||||||
|
}
|
||||||
|
|
||||||
|
(*env)->CallVoidMethod(env, wrapper_widget->jobj, wrapper_widget->draw_method, wrapper_widget->canvas);
|
||||||
|
|
||||||
|
if((*env)->ExceptionCheck(env))
|
||||||
|
(*env)->ExceptionDescribe(env);
|
||||||
|
|
||||||
|
cairo_destroy (cr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,3 +136,32 @@ void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child) // TODO:
|
|||||||
{
|
{
|
||||||
gtk_widget_insert_before(child, GTK_WIDGET(parent), NULL);
|
gtk_widget_insert_before(child, GTK_WIDGET(parent), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
(*env)->CallVoidMethod(env, wrapper->jobj, wrapper->measure_method, gtk_widget_get_width(self), gtk_widget_get_height(self));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
if (draw_method != handle_cache.view.onDraw)
|
||||||
|
wrapper->draw_method = draw_method;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
#ifndef WRAPPER_WIDGET_H
|
#ifndef WRAPPER_WIDGET_H
|
||||||
#define WRAPPER_WIDGET_H
|
#define WRAPPER_WIDGET_H
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE (WrapperWidget, wrapper_widget, WRAPPER, WIDGET, GtkWidget)
|
G_DECLARE_FINAL_TYPE (WrapperWidget, wrapper_widget, WRAPPER, WIDGET, GtkWidget)
|
||||||
|
|
||||||
struct _WrapperWidget
|
struct _WrapperWidget
|
||||||
{
|
{
|
||||||
GtkWidget parent_instance;
|
GtkWidget parent_instance;
|
||||||
|
JavaVM *jvm;
|
||||||
|
jobject jobj;
|
||||||
|
jobject canvas;
|
||||||
|
jmethodID draw_method;
|
||||||
|
jmethodID measure_method;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _WrapperWidgetClass
|
struct _WrapperWidgetClass
|
||||||
@@ -15,5 +22,6 @@ struct _WrapperWidgetClass
|
|||||||
|
|
||||||
GtkWidget * wrapper_widget_new(void);
|
GtkWidget * wrapper_widget_new(void);
|
||||||
void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child);
|
void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child);
|
||||||
|
void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject jobj);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ JNIEXPORT void JNICALL Java_android_widget_ImageView_native_1constructor__Landro
|
|||||||
GtkWidget *wrapper = wrapper_widget_new();
|
GtkWidget *wrapper = wrapper_widget_new();
|
||||||
GtkWidget *image = gtk_picture_new_for_resource("/org/gtk/libgtk/icons/16x16/status/image-missing.png"); // show "broken image" icon
|
GtkWidget *image = gtk_picture_new_for_resource("/org/gtk/libgtk/icons/16x16/status/image-missing.png"); // show "broken image" icon
|
||||||
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), image);
|
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), image);
|
||||||
|
wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this);
|
||||||
_SET_LONG_FIELD(this, "widget", _INTPTR(image));}
|
_SET_LONG_FIELD(this, "widget", _INTPTR(image));}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_android_widget_ImageView_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context)
|
JNIEXPORT void JNICALL Java_android_widget_ImageView_native_1constructor__Landroid_content_Context_2(JNIEnv *env, jobject this, jobject context)
|
||||||
@@ -19,6 +20,7 @@ JNIEXPORT void JNICALL Java_android_widget_ImageView_native_1constructor__Landro
|
|||||||
GtkWidget *wrapper = wrapper_widget_new();
|
GtkWidget *wrapper = wrapper_widget_new();
|
||||||
GtkWidget *image = gtk_picture_new_for_resource("/org/gtk/libgtk/icons/16x16/status/image-missing.png"); // show "broken image" icon
|
GtkWidget *image = gtk_picture_new_for_resource("/org/gtk/libgtk/icons/16x16/status/image-missing.png"); // show "broken image" icon
|
||||||
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), image);
|
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), image);
|
||||||
|
wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this);
|
||||||
_SET_LONG_FIELD(this, "widget", _INTPTR(image));
|
_SET_LONG_FIELD(this, "widget", _INTPTR(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user