diff --git a/src/api-impl-jni/generated_headers/android_widget_PopupWindow.h b/src/api-impl-jni/generated_headers/android_widget_PopupWindow.h index 3bf2d4fc..04d62668 100644 --- a/src/api-impl-jni/generated_headers/android_widget_PopupWindow.h +++ b/src/api-impl-jni/generated_headers/android_widget_PopupWindow.h @@ -39,6 +39,22 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1showAsDropDown JNIEXPORT jboolean JNICALL Java_android_widget_PopupWindow_native_1isShowing (JNIEnv *, jobject, jlong); +/* + * Class: android_widget_PopupWindow + * Method: native_setTouchable + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchable + (JNIEnv *, jobject, jlong, jboolean); + +/* + * Class: android_widget_PopupWindow + * Method: native_setTouchModal + * Signature: (JZ)V + */ +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchModal + (JNIEnv *, jobject, jlong, jboolean); + /* * Class: android_widget_PopupWindow * Method: native_dismiss @@ -65,19 +81,43 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setOnDismissListener /* * Class: android_widget_PopupWindow - * Method: setWidth - * Signature: (I)V + * Method: native_setWidth + * Signature: (JI)V */ -JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setWidth - (JNIEnv *, jobject, jint); +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setWidth + (JNIEnv *, jobject, jlong, jint); /* * Class: android_widget_PopupWindow - * Method: setHeight - * Signature: (I)V + * Method: native_setHeight + * Signature: (JI)V */ -JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setHeight - (JNIEnv *, jobject, jint); +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setHeight + (JNIEnv *, jobject, jlong, jint); + +/* + * Class: android_widget_PopupWindow + * Method: native_getWidth + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getWidth + (JNIEnv *, jobject, jlong); + +/* + * Class: android_widget_PopupWindow + * Method: native_getHeight + * Signature: (J)I + */ +JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getHeight + (JNIEnv *, jobject, jlong); + +/* + * Class: android_widget_PopupWindow + * Method: native_isTouchable + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_android_widget_PopupWindow_native_1isTouchable + (JNIEnv *, jobject, jlong); #ifdef __cplusplus } diff --git a/src/api-impl-jni/widgets/android_widget_PopupWindow.c b/src/api-impl-jni/widgets/android_widget_PopupWindow.c index f518cbfa..7e12d551 100644 --- a/src/api-impl-jni/widgets/android_widget_PopupWindow.c +++ b/src/api-impl-jni/widgets/android_widget_PopupWindow.c @@ -11,6 +11,8 @@ JNIEXPORT jlong JNICALL Java_android_widget_PopupWindow_native_1constructor(JNIE { GtkWidget *popover = gtk_popover_new(); gtk_widget_set_name(popover, "PopupWindow"); + /* autohiding works by the widget grabbing events, which is not something apps expect */ + gtk_popover_set_autohide(GTK_POPOVER(popover), false); return _INTPTR(popover); } @@ -20,32 +22,76 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setContentView(JN gtk_popover_set_child(GTK_POPOVER(_PTR(popover_ptr)), GTK_WIDGET(content)); } +static inline void set_offset(GtkPopover *popover, GtkWidget *anchor, int x, int y) +{ + /* FIXME: assumes GTK_POS_BOTTOM */ + gtk_popover_set_offset(popover, x - gtk_widget_get_width(anchor) / 2, y - gtk_widget_get_height(anchor)); +} + JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1showAsDropDown(JNIEnv *env, jobject this, jlong popover_ptr, jlong anchor_ptr, jint x, jint y, jint gravity) { GtkPopover *popover = GTK_POPOVER(_PTR(popover_ptr)); WrapperWidget *anchor = WRAPPER_WIDGET(gtk_widget_get_parent(GTK_WIDGET(_PTR(anchor_ptr)))); gtk_widget_insert_before(GTK_WIDGET(popover), GTK_WIDGET(anchor), NULL); + set_offset(popover, GTK_WIDGET(anchor), x, y); gtk_popover_present(GTK_POPOVER(popover)); gtk_popover_popup(popover); } -JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setWidth(JNIEnv *env, jobject this, jint width) +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setWidth(JNIEnv *env, jobject this, jlong popover_ptr, jint width) { int height; - GtkWidget *popover = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "popover"))); + GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr)); gtk_widget_get_size_request(popover, NULL, &height); gtk_widget_set_size_request(popover, width, height); } -JNIEXPORT void JNICALL Java_android_widget_PopupWindow_setHeight(JNIEnv *env, jobject this, jint height) +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setHeight(JNIEnv *env, jobject this, jlong popover_ptr, jint height) { int width; - GtkWidget *popover = GTK_WIDGET(_PTR(_GET_LONG_FIELD(this, "popover"))); + GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr)); gtk_widget_get_size_request(popover, &width, NULL); gtk_widget_set_size_request(popover, width, height); } +JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getWidth(JNIEnv *env, jobject this, jlong popover_ptr) +{ + GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr)); + GtkRequisition natural_size; + gtk_widget_get_preferred_size(popover, &natural_size, NULL); + return natural_size.width; +} + +JNIEXPORT jint JNICALL Java_android_widget_PopupWindow_native_1getHeight(JNIEnv *env, jobject this, jlong popover_ptr) +{ + GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr)); + GtkRequisition natural_size; + gtk_widget_get_preferred_size(popover, &natural_size, NULL); + return natural_size.height; +} + +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchable(JNIEnv *env, jobject this, jlong popover_ptr, jboolean touchable) +{ + GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr)); + gtk_widget_set_sensitive(popover, touchable); +} + +JNIEXPORT jboolean JNICALL Java_android_widget_PopupWindow_native_1isTouchable(JNIEnv *env, jobject this, jlong popover_ptr) +{ + GtkWidget *popover = GTK_WIDGET(_PTR(popover_ptr)); + return gtk_widget_is_sensitive(popover); +} + +JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1setTouchModal(JNIEnv *env, jobject this, jlong popover_ptr, jboolean touch_modal) +{ + GtkPopover *popover = GTK_POPOVER(_PTR(popover_ptr)); + /* FIXME: we should only add grab (not autohide), however we need to remove it again in umap; + * GtkPopover is not final, so we should subclass it and check whether it's modal in map/unmap + * to add/remove grab, which is the desired part of what GtkPopover does with autohide enabled */ + gtk_popover_set_autohide(popover, touch_modal); +} + static void on_closed_cb(GtkPopover *popover, jobject listener) { JNIEnv *env = get_jni_env(); @@ -74,6 +120,7 @@ JNIEXPORT void JNICALL Java_android_widget_PopupWindow_native_1update(JNIEnv *en GtkPopover *popover = GTK_POPOVER(_PTR(popover_ptr)); WrapperWidget *anchor = WRAPPER_WIDGET(gtk_widget_get_parent(GTK_WIDGET(_PTR(anchor_ptr)))); gtk_widget_set_size_request(GTK_WIDGET(popover), width, height); + set_offset(popover, GTK_WIDGET(anchor), x, y); gtk_widget_insert_before(GTK_WIDGET(popover), GTK_WIDGET(anchor), NULL); gtk_popover_present(GTK_POPOVER(popover)); gtk_popover_popup(popover); diff --git a/src/api-impl/android/widget/PopupWindow.java b/src/api-impl/android/widget/PopupWindow.java index 5e0abe64..a63a9133 100644 --- a/src/api-impl/android/widget/PopupWindow.java +++ b/src/api-impl/android/widget/PopupWindow.java @@ -10,6 +10,8 @@ import android.view.View; public class PopupWindow { + int input_method_mode = 0; + public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { popover = native_constructor(); } @@ -41,23 +43,25 @@ public class PopupWindow { public void onDismiss(); } - protected native long native_constructor(); - protected native void native_setContentView(long widget, long contentView); - protected native void native_showAsDropDown(long widget, long anchor, int xoff, int yoff, int gravity); - protected native boolean native_isShowing(long widget); - protected native void native_dismiss(long widget); - protected native void native_update(long widget, long anchor, int xoff, int yoff, int width, int height); + public void setBackgroundDrawable(Drawable background) { + /* FIXME: use a decorview? */ + if(contentView != null) { + contentView.setBackgroundDrawable(background); + } + } - public void setBackgroundDrawable(Drawable background) {} + public void setInputMethodMode(int mode) { + input_method_mode = mode; + } - public void setInputMethodMode(int mode) {} + public int getInputMethodMode() { + return input_method_mode; + } public boolean isShowing() { return native_isShowing(popover); } - public native void setOnDismissListener(OnDismissListener listener); - public void setFocusable(boolean focusable) {} public Drawable getBackground() {return null;} @@ -70,17 +74,16 @@ public class PopupWindow { native_setContentView(popover, view == null ? 0 : view.widget); } - public int getInputMethodMode() {return 0;} - public int getMaxAvailableHeight(View anchor, int yOffset) {return 500;} public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreKeyboard) {return 500;} - public native void setWidth(int width); - - public native void setHeight(int height); - - public void setOutsideTouchable(boolean touchable) {} + public void setOutsideTouchable(boolean touchable) { + /* FIXME: the semantics are different, this seems to specifically exist for cases + * where the popup is *not* modal, so that in addition to the window behind getting + * the real event, the popup gets a special MotionEvent.ACTION_OUTSIDE event */ + native_setTouchModal(popover, touchable); + } public void setTouchInterceptor(View.OnTouchListener listener) {} @@ -88,9 +91,13 @@ public class PopupWindow { native_showAsDropDown(popover, anchor.widget, xoff, yoff, gravity); } - public View getContentView() {return contentView;} + public View getContentView() { + return contentView; + } - public void setTouchable(boolean touchable) {} + public void setTouchable(boolean touchable) { + native_setTouchable(popover, touchable); + } public void showAsDropDown(View anchor, int xoff, int yoff) { if (!anchor.isAttachedToWindow()) { @@ -110,7 +117,9 @@ public class PopupWindow { public void setAnimationStyle(int animationStyle) {} - public void setTouchModal(boolean touchModal) {} + public void setTouchModal(boolean touchModal) { + native_setTouchModal(popover, touchModal); + } public void setElevation(float elevation) {} @@ -123,4 +132,53 @@ public class PopupWindow { public void setIsClippedToScreen(boolean isClippedToScreen) {} public void setEpicenterBounds(Rect bounds) {} + + public void setClippingEnabled(boolean enabled) {} + + /* TODO: handle LayoutParams.WRAP_CONTENT and LayoutParams.MATCH_PARENT */ + public void setWidth(int width) { + if(width < 0) + return; + + native_setWidth(popover, width); + } + + public void setHeight(int height) { + if(height < 0) + return; + + native_setHeight(popover, height); + } + + public int getWidth() { + return native_getWidth(popover); + } + + public int getHeight() { + return native_getHeight(popover); + } + + public void update(int x, int y, int width, int height) {} + + public void setWindowLayoutMode(int widthSpec, int heightSpec) {} + + + public boolean isTouchable() { + return native_isTouchable(popover); + } + + protected native long native_constructor(); + protected native void native_setContentView(long widget, long contentView); + protected native void native_showAsDropDown(long widget, long anchor, int xoff, int yoff, int gravity); + protected native boolean native_isShowing(long widget); + protected native void native_setTouchable(long widget, boolean touchable); + protected native void native_setTouchModal(long widget, boolean touchable); + protected native void native_dismiss(long widget); + protected native void native_update(long widget, long anchor, int xoff, int yoff, int width, int height); + public native void setOnDismissListener(OnDismissListener listener); + public native void native_setWidth(long widget, int width); + public native void native_setHeight(long widget, int height); + public native int native_getWidth(long widget); + public native int native_getHeight(long widget); + public native boolean native_isTouchable(long widget); }