diff options
author | Eric Williams | 2018-02-28 21:10:48 +0000 |
---|---|---|
committer | Eric Williams | 2018-03-01 15:05:58 +0000 |
commit | 272bf0d8ebce8f12e9bb0de2c389d3a18d319afb (patch) | |
tree | 80cd8d78c74581898c96273142bed3484ab0203a /bundles/org.eclipse.swt/Eclipse SWT PI/gtk | |
parent | 64ef68738d8d1ef74937fc86faea774baa48287d (diff) | |
download | eclipse.platform.swt-272bf0d8ebce8f12e9bb0de2c389d3a18d319afb.tar.gz eclipse.platform.swt-272bf0d8ebce8f12e9bb0de2c389d3a18d319afb.tar.xz eclipse.platform.swt-272bf0d8ebce8f12e9bb0de2c389d3a18d319afb.zip |
Bug 431423: [GTK3] Context menu should appear by pointer when invoked
via mouse
Some context menus are positioned incorrectly when the size (number of
items) of the menu changes between clicks.
The cause of this bug is due to the way SWT populates its menus: often
it is done asynchronously outside of SWT based on an SWT.Show listener.
The result is that the menu items are added/removed just before showing,
and GTK sometimes doesn't have enough time to properly adjust the size
of the menu internally. Specifically, the GdkWindow of the toplevel
widget (GtkWindow) for the menu lags in height. Since GTK thinks the
menu is taller/shorter than it is, the menu is positioned at the wrong
y-coordinate.
The fix is to check if the number of menu items has changed from one
pop-up to the next. If so, calculate the preferred height of the menu
and resize the GdkWindow of the menu's toplevel GtkWindow to reflect
this change. This way the internal sizing calculations in GTK will be
accurate and the menu will be positioned correctly.
The bug is fixed on GTK3.22 with X11 only, as this uses the new GTK3.22
GtkMenu API. Older GTK3 versions use the outdated GtkMenu API and fixing
these cases would not be worth the effort. Wayland is not affected by
this bug.
Reliable steps to reproduce the issue can be found here:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=431423#c19
Tested JFace/SWT menu snippets, AllNonBrowser JUnit tests, and
ControlExample on GTK3.22 with X11.
Change-Id: I392983438cc32b9455c53cc464626294f3ec72f9
Signed-off-by: Eric Williams <ericwill@redhat.com>
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT PI/gtk')
4 files changed, 39 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c index 428d448027..7cddab1bdb 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c @@ -13328,6 +13328,31 @@ JNIEXPORT jintLong JNICALL GTK_NATIVE(_1gtk_1widget_1get_1parent_1window) } #endif +#ifndef NO__1gtk_1widget_1get_1preferred_1height +JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1widget_1get_1preferred_1height) + (JNIEnv *env, jclass that, jintLong arg0, jintArray arg1, jintArray arg2) +{ + jint *lparg1=NULL; + jint *lparg2=NULL; + GTK_NATIVE_ENTER(env, that, _1gtk_1widget_1get_1preferred_1height_FUNC); + if (arg1) if ((lparg1 = (*env)->GetIntArrayElements(env, arg1, NULL)) == NULL) goto fail; + if (arg2) if ((lparg2 = (*env)->GetIntArrayElements(env, arg2, NULL)) == NULL) goto fail; +/* + gtk_widget_get_preferred_height(arg0, lparg1, lparg2); +*/ + { + GTK_LOAD_FUNCTION(fp, gtk_widget_get_preferred_height) + if (fp) { + ((void (CALLING_CONVENTION*)(jintLong, jint *, jint *))fp)(arg0, lparg1, lparg2); + } + } +fail: + if (arg2 && lparg2) (*env)->ReleaseIntArrayElements(env, arg2, lparg2, 0); + if (arg1 && lparg1) (*env)->ReleaseIntArrayElements(env, arg1, lparg1, 0); + GTK_NATIVE_EXIT(env, that, _1gtk_1widget_1get_1preferred_1height_FUNC); +} +#endif + #ifndef NO__1gtk_1widget_1get_1preferred_1height_1for_1width JNIEXPORT void JNICALL GTK_NATIVE(_1gtk_1widget_1get_1preferred_1height_1for_1width) (JNIEnv *env, jclass that, jintLong arg0, jint arg1, jintArray arg2, jintArray arg3) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c index ddb326eacf..43acdb330e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c @@ -1068,6 +1068,7 @@ char * GTK_nativeFunctionNames[] = { "_1gtk_1widget_1get_1pango_1context", "_1gtk_1widget_1get_1parent", "_1gtk_1widget_1get_1parent_1window", + "_1gtk_1widget_1get_1preferred_1height", "_1gtk_1widget_1get_1preferred_1height_1for_1width", "_1gtk_1widget_1get_1preferred_1size", "_1gtk_1widget_1get_1preferred_1width_1for_1height", diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h index f8fd88f489..2038eea393 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h @@ -1066,6 +1066,7 @@ typedef enum { _1gtk_1widget_1get_1pango_1context_FUNC, _1gtk_1widget_1get_1parent_FUNC, _1gtk_1widget_1get_1parent_1window_FUNC, + _1gtk_1widget_1get_1preferred_1height_FUNC, _1gtk_1widget_1get_1preferred_1height_1for_1width_FUNC, _1gtk_1widget_1get_1preferred_1size_FUNC, _1gtk_1widget_1get_1preferred_1width_1for_1height_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java index a343cfef7f..a324248031 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java @@ -1143,6 +1143,18 @@ public class GTK extends OS { /** * @method flags=dynamic */ + public static final native void _gtk_widget_get_preferred_height(long /*int*/ widget, int[] minimum_size, int[] natural_size); + public static final void gtk_widget_get_preferred_height(long /*int*/ widget, int[] minimum_size, int[] natural_size) { + lock.lock(); + try { + _gtk_widget_get_preferred_height(widget, minimum_size, natural_size); + } finally { + lock.unlock(); + } + } + /** + * @method flags=dynamic + */ public static final native void _gtk_widget_get_preferred_width_for_height(long /*int*/ widget, int height, int[] minimum_size, int[] natural_size); public static final void gtk_widget_get_preferred_width_for_height(long /*int*/ widget, int height, int[] minimum_size, int[] natural_size) { lock.lock(); |