Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandr Miloslavskiy2019-05-08 10:02:53 -0400
committerEric Williams2019-05-17 15:48:40 -0400
commit929b63844fbc2a382b7bd182abadf81b45dc04d3 (patch)
treef50a16f6126fecb3ec9ba0403e2ed53319f9ae83
parentd119e6e20762735d3205896d791bf71952dc31ec (diff)
downloadeclipse.platform.swt-929b63844fbc2a382b7bd182abadf81b45dc04d3.tar.gz
eclipse.platform.swt-929b63844fbc2a382b7bd182abadf81b45dc04d3.tar.xz
eclipse.platform.swt-929b63844fbc2a382b7bd182abadf81b45dc04d3.zip
Bug 547093 - [GTK] GNOME logoff hangs for 90 seconds after System.exit() on SWT.Dispose for Display
Change 1 -------- Fixed the session manager hang. It started to happen after Bug 531634, on GNOME only. The problem is caused by a combination of System.exit() during 'SWT.Dispose' for 'Display' in SWT application and an oversight in GNOME session-manager [1]. Due to System.exit() SWT's 'SessionManagerDBus' doesn't have a chance to respond with 'EndSessionResponse' and GNOME's session manager gets stuck waiting for the reply. Change 2 -------- Removed lock from APIs needed in shutdown hook to avoid the deadlock. Lock is a problem because java's shutdown hooks are implemented as separate threads, and the main thread will hold lock, because session manager signals are dispatched in 'g_main_context_iteration'. The lock shouldn't be used so often anyway, see Bug 546743. Change 3 -------- Fixed incorrect behavior when QueryEndSession shows a message box and when user closes it, QueryEndSession timeout elapsed and session manager expects answer to EndSession instead. [1] https://gitlab.gnome.org/GNOME/gnome-session/merge_requests/15 Change-Id: I891f2b15830caafc73ccfa6491a8f21c2bbc0160 Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c282
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c16
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h16
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java92
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SessionManagerDBus.java116
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547093_LogoffStuck.java56
6 files changed, 337 insertions, 241 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 8e32951ff9..f88e3fd40d 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
@@ -14754,23 +14754,6 @@ fail:
}
#endif
-#ifndef NO__1g_1dbus_1proxy_1call
-JNIEXPORT void JNICALL OS_NATIVE(_1g_1dbus_1proxy_1call)
- (JNIEnv *env, jclass that, jlong arg0, jbyteArray arg1, jlong arg2, jint arg3, jint arg4, jlong arg5, jlong arg6, jlongArray arg7)
-{
- jbyte *lparg1=NULL;
- jlong *lparg7=NULL;
- OS_NATIVE_ENTER(env, that, _1g_1dbus_1proxy_1call_FUNC);
- if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
- if (arg7) if ((lparg7 = (*env)->GetLongArrayElements(env, arg7, NULL)) == NULL) goto fail;
- g_dbus_proxy_call((GDBusProxy *)arg0, (const gchar *)lparg1, (GVariant *)arg2, arg3, arg4, (GCancellable *)arg5, (GAsyncReadyCallback)arg6, (GError **)lparg7);
-fail:
- if (arg7 && lparg7) (*env)->ReleaseLongArrayElements(env, arg7, lparg7, 0);
- if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
- OS_NATIVE_EXIT(env, that, _1g_1dbus_1proxy_1call_FUNC);
-}
-#endif
-
#ifndef NO__1g_1dbus_1proxy_1call_1finish
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1dbus_1proxy_1call_1finish)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1, jlongArray arg2)
@@ -14787,25 +14770,6 @@ fail:
}
#endif
-#ifndef NO__1g_1dbus_1proxy_1call_1sync
-JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1dbus_1proxy_1call_1sync)
- (JNIEnv *env, jclass that, jlong arg0, jbyteArray arg1, jlong arg2, jint arg3, jint arg4, jlong arg5, jlongArray arg6)
-{
- jbyte *lparg1=NULL;
- jlong *lparg6=NULL;
- jlong rc = 0;
- OS_NATIVE_ENTER(env, that, _1g_1dbus_1proxy_1call_1sync_FUNC);
- if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
- if (arg6) if ((lparg6 = (*env)->GetLongArrayElements(env, arg6, NULL)) == NULL) goto fail;
- rc = (jlong)g_dbus_proxy_call_sync((GDBusProxy *)arg0, (const gchar *)lparg1, (GVariant *)arg2, arg3, arg4, (GCancellable *)arg5, (GError **)lparg6);
-fail:
- if (arg6 && lparg6) (*env)->ReleaseLongArrayElements(env, arg6, lparg6, 0);
- if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
- OS_NATIVE_EXIT(env, that, _1g_1dbus_1proxy_1call_1sync_FUNC);
- return rc;
-}
-#endif
-
#ifndef NO__1g_1dbus_1proxy_1get_1name_1owner
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1dbus_1proxy_1get_1name_1owner)
(JNIEnv *env, jclass that, jlong arg0)
@@ -15060,16 +15024,6 @@ fail:
}
#endif
-#ifndef NO__1g_1free
-JNIEXPORT void JNICALL OS_NATIVE(_1g_1free)
- (JNIEnv *env, jclass that, jlong arg0)
-{
- OS_NATIVE_ENTER(env, that, _1g_1free_FUNC);
- g_free((gpointer)arg0);
- OS_NATIVE_EXIT(env, that, _1g_1free_FUNC);
-}
-#endif
-
#ifndef NO__1g_1get_1current_1time
JNIEXPORT void JNICALL OS_NATIVE(_1g_1get_1current_1time)
(JNIEnv *env, jclass that, jlong arg0)
@@ -15677,16 +15631,6 @@ JNIEXPORT void JNICALL OS_NATIVE(_1g_1object_1set_1qdata)
}
#endif
-#ifndef NO__1g_1object_1unref
-JNIEXPORT void JNICALL OS_NATIVE(_1g_1object_1unref)
- (JNIEnv *env, jclass that, jlong arg0)
-{
- OS_NATIVE_ENTER(env, that, _1g_1object_1unref_FUNC);
- g_object_unref((gpointer)arg0);
- OS_NATIVE_EXIT(env, that, _1g_1object_1unref_FUNC);
-}
-#endif
-
#ifndef NO__1g_1quark_1from_1string
JNIEXPORT jint JNICALL OS_NATIVE(_1g_1quark_1from_1string)
(JNIEnv *env, jclass that, jbyteArray arg0)
@@ -16257,31 +16201,6 @@ JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1utf16_1strlen)
}
#endif
-#ifndef NO__1g_1utf16_1to_1utf8
-JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1utf16_1to_1utf8)
- (JNIEnv *env, jclass that, jcharArray arg0, jlong arg1, jlongArray arg2, jlongArray arg3, jlongArray arg4)
-{
- jchar *lparg0=NULL;
- jlong *lparg2=NULL;
- jlong *lparg3=NULL;
- jlong *lparg4=NULL;
- jlong rc = 0;
- OS_NATIVE_ENTER(env, that, _1g_1utf16_1to_1utf8_FUNC);
- if (arg0) if ((lparg0 = (*env)->GetPrimitiveArrayCritical(env, arg0, NULL)) == NULL) goto fail;
- if (arg2) if ((lparg2 = (*env)->GetPrimitiveArrayCritical(env, arg2, NULL)) == NULL) goto fail;
- if (arg3) if ((lparg3 = (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) == NULL) goto fail;
- if (arg4) if ((lparg4 = (*env)->GetPrimitiveArrayCritical(env, arg4, NULL)) == NULL) goto fail;
- rc = (jlong)g_utf16_to_utf8((const gunichar2 *)lparg0, (glong)arg1, (glong *)lparg2, (glong *)lparg3, (GError **)lparg4);
-fail:
- if (arg4 && lparg4) (*env)->ReleasePrimitiveArrayCritical(env, arg4, lparg4, 0);
- if (arg3 && lparg3) (*env)->ReleasePrimitiveArrayCritical(env, arg3, lparg3, 0);
- if (arg2 && lparg2) (*env)->ReleasePrimitiveArrayCritical(env, arg2, lparg2, 0);
- if (arg0 && lparg0) (*env)->ReleasePrimitiveArrayCritical(env, arg0, lparg0, JNI_ABORT);
- OS_NATIVE_EXIT(env, that, _1g_1utf16_1to_1utf8_FUNC);
- return rc;
-}
-#endif
-
#ifndef NO__1g_1utf8_1offset_1to_1utf16_1offset
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1utf8_1offset_1to_1utf16_1offset)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1)
@@ -16561,66 +16480,6 @@ JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1n_1children)
}
#endif
-#ifndef NO__1g_1variant_1new___3BZ_3B
-JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1new___3BZ_3B)
- (JNIEnv *env, jclass that, jbyteArray arg0, jboolean arg1, jbyteArray arg2)
-{
- jbyte *lparg0=NULL;
- jbyte *lparg2=NULL;
- jlong rc = 0;
- OS_NATIVE_ENTER(env, that, _1g_1variant_1new___3BZ_3B_FUNC);
- if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
- if (arg2) if ((lparg2 = (*env)->GetByteArrayElements(env, arg2, NULL)) == NULL) goto fail;
- rc = (jlong)g_variant_new((const gchar *)lparg0, (gboolean)arg1, (const gchar *)lparg2);
-fail:
- if (arg2 && lparg2) (*env)->ReleaseByteArrayElements(env, arg2, lparg2, JNI_ABORT);
- if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
- OS_NATIVE_EXIT(env, that, _1g_1variant_1new___3BZ_3B_FUNC);
- return rc;
-}
-#endif
-
-#ifndef NO__1g_1variant_1new___3B_3B
-JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1new___3B_3B)
- (JNIEnv *env, jclass that, jbyteArray arg0, jbyteArray arg1)
-{
- jbyte *lparg0=NULL;
- jbyte *lparg1=NULL;
- jlong rc = 0;
- OS_NATIVE_ENTER(env, that, _1g_1variant_1new___3B_3B_FUNC);
- if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
- if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
- rc = (jlong)g_variant_new((const gchar *)lparg0, (const gchar *)lparg1);
-fail:
- if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, JNI_ABORT);
- if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
- OS_NATIVE_EXIT(env, that, _1g_1variant_1new___3B_3B_FUNC);
- return rc;
-}
-#endif
-
-#ifndef NO__1g_1variant_1new___3B_3B_3B
-JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1new___3B_3B_3B)
- (JNIEnv *env, jclass that, jbyteArray arg0, jbyteArray arg1, jbyteArray arg2)
-{
- jbyte *lparg0=NULL;
- jbyte *lparg1=NULL;
- jbyte *lparg2=NULL;
- jlong rc = 0;
- OS_NATIVE_ENTER(env, that, _1g_1variant_1new___3B_3B_3B_FUNC);
- if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
- if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
- if (arg2) if ((lparg2 = (*env)->GetByteArrayElements(env, arg2, NULL)) == NULL) goto fail;
- rc = (jlong)g_variant_new((const gchar *)lparg0, (const gchar *)lparg1, (const gchar *)lparg2);
-fail:
- if (arg2 && lparg2) (*env)->ReleaseByteArrayElements(env, arg2, lparg2, JNI_ABORT);
- if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, JNI_ABORT);
- if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
- OS_NATIVE_EXIT(env, that, _1g_1variant_1new___3B_3B_3B_FUNC);
- return rc;
-}
-#endif
-
#ifndef NO__1g_1variant_1new_1boolean
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1new_1boolean)
(JNIEnv *env, jclass that, jboolean arg0)
@@ -18045,6 +17904,52 @@ JNIEXPORT jlong JNICALL OS_NATIVE(_1ubuntu_1menu_1proxy_1get)
}
#endif
+#ifndef NO_g_1dbus_1proxy_1call
+JNIEXPORT void JNICALL OS_NATIVE(g_1dbus_1proxy_1call)
+ (JNIEnv *env, jclass that, jlong arg0, jbyteArray arg1, jlong arg2, jint arg3, jint arg4, jlong arg5, jlong arg6, jlongArray arg7)
+{
+ jbyte *lparg1=NULL;
+ jlong *lparg7=NULL;
+ OS_NATIVE_ENTER(env, that, g_1dbus_1proxy_1call_FUNC);
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg7) if ((lparg7 = (*env)->GetLongArrayElements(env, arg7, NULL)) == NULL) goto fail;
+ g_dbus_proxy_call((GDBusProxy *)arg0, (const gchar *)lparg1, (GVariant *)arg2, arg3, arg4, (GCancellable *)arg5, (GAsyncReadyCallback)arg6, (GError **)lparg7);
+fail:
+ if (arg7 && lparg7) (*env)->ReleaseLongArrayElements(env, arg7, lparg7, 0);
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
+ OS_NATIVE_EXIT(env, that, g_1dbus_1proxy_1call_FUNC);
+}
+#endif
+
+#ifndef NO_g_1dbus_1proxy_1call_1sync
+JNIEXPORT jlong JNICALL OS_NATIVE(g_1dbus_1proxy_1call_1sync)
+ (JNIEnv *env, jclass that, jlong arg0, jbyteArray arg1, jlong arg2, jint arg3, jint arg4, jlong arg5, jlongArray arg6)
+{
+ jbyte *lparg1=NULL;
+ jlong *lparg6=NULL;
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, g_1dbus_1proxy_1call_1sync_FUNC);
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg6) if ((lparg6 = (*env)->GetLongArrayElements(env, arg6, NULL)) == NULL) goto fail;
+ rc = (jlong)g_dbus_proxy_call_sync((GDBusProxy *)arg0, (const gchar *)lparg1, (GVariant *)arg2, arg3, arg4, (GCancellable *)arg5, (GError **)lparg6);
+fail:
+ if (arg6 && lparg6) (*env)->ReleaseLongArrayElements(env, arg6, lparg6, 0);
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, 0);
+ OS_NATIVE_EXIT(env, that, g_1dbus_1proxy_1call_1sync_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO_g_1free
+JNIEXPORT void JNICALL OS_NATIVE(g_1free)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ OS_NATIVE_ENTER(env, that, g_1free_FUNC);
+ g_free((gpointer)arg0);
+ OS_NATIVE_EXIT(env, that, g_1free_FUNC);
+}
+#endif
+
#ifndef NO_g_1main_1context_1wakeup
JNIEXPORT void JNICALL OS_NATIVE(g_1main_1context_1wakeup)
(JNIEnv *env, jclass that, jlong arg0)
@@ -18055,6 +17960,16 @@ JNIEXPORT void JNICALL OS_NATIVE(g_1main_1context_1wakeup)
}
#endif
+#ifndef NO_g_1object_1unref
+JNIEXPORT void JNICALL OS_NATIVE(g_1object_1unref)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ OS_NATIVE_ENTER(env, that, g_1object_1unref_FUNC);
+ g_object_unref((gpointer)arg0);
+ OS_NATIVE_EXIT(env, that, g_1object_1unref_FUNC);
+}
+#endif
+
#ifndef NO_g_1strdup
JNIEXPORT jlong JNICALL OS_NATIVE(g_1strdup)
(JNIEnv *env, jclass that, jlong arg0)
@@ -18067,6 +17982,31 @@ JNIEXPORT jlong JNICALL OS_NATIVE(g_1strdup)
}
#endif
+#ifndef NO_g_1utf16_1to_1utf8
+JNIEXPORT jlong JNICALL OS_NATIVE(g_1utf16_1to_1utf8)
+ (JNIEnv *env, jclass that, jcharArray arg0, jlong arg1, jlongArray arg2, jlongArray arg3, jlongArray arg4)
+{
+ jchar *lparg0=NULL;
+ jlong *lparg2=NULL;
+ jlong *lparg3=NULL;
+ jlong *lparg4=NULL;
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, g_1utf16_1to_1utf8_FUNC);
+ if (arg0) if ((lparg0 = (*env)->GetPrimitiveArrayCritical(env, arg0, NULL)) == NULL) goto fail;
+ if (arg2) if ((lparg2 = (*env)->GetPrimitiveArrayCritical(env, arg2, NULL)) == NULL) goto fail;
+ if (arg3) if ((lparg3 = (*env)->GetPrimitiveArrayCritical(env, arg3, NULL)) == NULL) goto fail;
+ if (arg4) if ((lparg4 = (*env)->GetPrimitiveArrayCritical(env, arg4, NULL)) == NULL) goto fail;
+ rc = (jlong)g_utf16_to_utf8((const gunichar2 *)lparg0, (glong)arg1, (glong *)lparg2, (glong *)lparg3, (GError **)lparg4);
+fail:
+ if (arg4 && lparg4) (*env)->ReleasePrimitiveArrayCritical(env, arg4, lparg4, 0);
+ if (arg3 && lparg3) (*env)->ReleasePrimitiveArrayCritical(env, arg3, lparg3, 0);
+ if (arg2 && lparg2) (*env)->ReleasePrimitiveArrayCritical(env, arg2, lparg2, 0);
+ if (arg0 && lparg0) (*env)->ReleasePrimitiveArrayCritical(env, arg0, lparg0, JNI_ABORT);
+ OS_NATIVE_EXIT(env, that, g_1utf16_1to_1utf8_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO_g_1value_1get_1double
JNIEXPORT jdouble JNICALL OS_NATIVE(g_1value_1get_1double)
(JNIEnv *env, jclass that, jlong arg0)
@@ -18177,6 +18117,66 @@ JNIEXPORT void JNICALL OS_NATIVE(g_1value_1unset)
}
#endif
+#ifndef NO_g_1variant_1new___3BZ_3B
+JNIEXPORT jlong JNICALL OS_NATIVE(g_1variant_1new___3BZ_3B)
+ (JNIEnv *env, jclass that, jbyteArray arg0, jboolean arg1, jbyteArray arg2)
+{
+ jbyte *lparg0=NULL;
+ jbyte *lparg2=NULL;
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, g_1variant_1new___3BZ_3B_FUNC);
+ if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
+ if (arg2) if ((lparg2 = (*env)->GetByteArrayElements(env, arg2, NULL)) == NULL) goto fail;
+ rc = (jlong)g_variant_new((const gchar *)lparg0, (gboolean)arg1, (const gchar *)lparg2);
+fail:
+ if (arg2 && lparg2) (*env)->ReleaseByteArrayElements(env, arg2, lparg2, JNI_ABORT);
+ if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
+ OS_NATIVE_EXIT(env, that, g_1variant_1new___3BZ_3B_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO_g_1variant_1new___3B_3B
+JNIEXPORT jlong JNICALL OS_NATIVE(g_1variant_1new___3B_3B)
+ (JNIEnv *env, jclass that, jbyteArray arg0, jbyteArray arg1)
+{
+ jbyte *lparg0=NULL;
+ jbyte *lparg1=NULL;
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, g_1variant_1new___3B_3B_FUNC);
+ if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ rc = (jlong)g_variant_new((const gchar *)lparg0, (const gchar *)lparg1);
+fail:
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, JNI_ABORT);
+ if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
+ OS_NATIVE_EXIT(env, that, g_1variant_1new___3B_3B_FUNC);
+ return rc;
+}
+#endif
+
+#ifndef NO_g_1variant_1new___3B_3B_3B
+JNIEXPORT jlong JNICALL OS_NATIVE(g_1variant_1new___3B_3B_3B)
+ (JNIEnv *env, jclass that, jbyteArray arg0, jbyteArray arg1, jbyteArray arg2)
+{
+ jbyte *lparg0=NULL;
+ jbyte *lparg1=NULL;
+ jbyte *lparg2=NULL;
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, g_1variant_1new___3B_3B_3B_FUNC);
+ if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
+ if (arg1) if ((lparg1 = (*env)->GetByteArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg2) if ((lparg2 = (*env)->GetByteArrayElements(env, arg2, NULL)) == NULL) goto fail;
+ rc = (jlong)g_variant_new((const gchar *)lparg0, (const gchar *)lparg1, (const gchar *)lparg2);
+fail:
+ if (arg2 && lparg2) (*env)->ReleaseByteArrayElements(env, arg2, lparg2, JNI_ABORT);
+ if (arg1 && lparg1) (*env)->ReleaseByteArrayElements(env, arg1, lparg1, JNI_ABORT);
+ if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
+ OS_NATIVE_EXIT(env, that, g_1variant_1new___3B_3B_3B_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO_localeconv_1decimal_1point
JNIEXPORT jlong JNICALL OS_NATIVE(localeconv_1decimal_1point)
(JNIEnv *env, jclass that)
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 b0eac77a80..3d9d40141a 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
@@ -1222,9 +1222,7 @@ char * OS_nativeFunctionNames[] = {
"_1g_1dbus_1method_1invocation_1return_1value",
"_1g_1dbus_1node_1info_1lookup_1interface",
"_1g_1dbus_1node_1info_1new_1for_1xml",
- "_1g_1dbus_1proxy_1call",
"_1g_1dbus_1proxy_1call_1finish",
- "_1g_1dbus_1proxy_1call_1sync",
"_1g_1dbus_1proxy_1get_1name_1owner",
"_1g_1dbus_1proxy_1new_1for_1bus_1sync",
"_1g_1error_1free",
@@ -1241,7 +1239,6 @@ char * OS_nativeFunctionNames[] = {
"_1g_1filename_1from_1utf8",
"_1g_1filename_1to_1uri",
"_1g_1filename_1to_1utf8",
- "_1g_1free",
"_1g_1get_1current_1time",
"_1g_1getenv",
"_1g_1hash_1table_1get_1values",
@@ -1289,7 +1286,6 @@ char * OS_nativeFunctionNames[] = {
"_1g_1object_1set__J_3BZJ",
"_1g_1object_1set__J_3B_3BJ",
"_1g_1object_1set_1qdata",
- "_1g_1object_1unref",
"_1g_1quark_1from_1string",
"_1g_1set_1prgname",
"_1g_1signal_1add_1emission_1hook",
@@ -1335,7 +1331,6 @@ char * OS_nativeFunctionNames[] = {
"_1g_1utf16_1offset_1to_1utf8_1offset",
"_1g_1utf16_1pointer_1to_1offset",
"_1g_1utf16_1strlen",
- "_1g_1utf16_1to_1utf8",
"_1g_1utf8_1offset_1to_1utf16_1offset",
"_1g_1utf8_1pointer_1to_1offset",
"_1g_1utf8_1strlen",
@@ -1357,9 +1352,6 @@ char * OS_nativeFunctionNames[] = {
"_1g_1variant_1get_1uint64",
"_1g_1variant_1is_1of_1type",
"_1g_1variant_1n_1children",
- "_1g_1variant_1new___3BZ_3B",
- "_1g_1variant_1new___3B_3B",
- "_1g_1variant_1new___3B_3B_3B",
"_1g_1variant_1new_1boolean",
"_1g_1variant_1new_1byte",
"_1g_1variant_1new_1double",
@@ -1478,8 +1470,13 @@ char * OS_nativeFunctionNames[] = {
"_1swt_1fixed_1resize",
"_1swt_1fixed_1restack",
"_1ubuntu_1menu_1proxy_1get",
+ "g_1dbus_1proxy_1call",
+ "g_1dbus_1proxy_1call_1sync",
+ "g_1free",
"g_1main_1context_1wakeup",
+ "g_1object_1unref",
"g_1strdup",
+ "g_1utf16_1to_1utf8",
"g_1value_1get_1double",
"g_1value_1get_1float",
"g_1value_1get_1int",
@@ -1490,6 +1487,9 @@ char * OS_nativeFunctionNames[] = {
"g_1value_1set_1int",
"g_1value_1set_1int64",
"g_1value_1unset",
+ "g_1variant_1new___3BZ_3B",
+ "g_1variant_1new___3B_3B",
+ "g_1variant_1new___3B_3B_3B",
"imContextLast",
"imContextNewProc_1CALLBACK",
"localeconv_1decimal_1point",
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 5145d14c27..acb253ec53 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
@@ -1196,9 +1196,7 @@ typedef enum {
_1g_1dbus_1method_1invocation_1return_1value_FUNC,
_1g_1dbus_1node_1info_1lookup_1interface_FUNC,
_1g_1dbus_1node_1info_1new_1for_1xml_FUNC,
- _1g_1dbus_1proxy_1call_FUNC,
_1g_1dbus_1proxy_1call_1finish_FUNC,
- _1g_1dbus_1proxy_1call_1sync_FUNC,
_1g_1dbus_1proxy_1get_1name_1owner_FUNC,
_1g_1dbus_1proxy_1new_1for_1bus_1sync_FUNC,
_1g_1error_1free_FUNC,
@@ -1215,7 +1213,6 @@ typedef enum {
_1g_1filename_1from_1utf8_FUNC,
_1g_1filename_1to_1uri_FUNC,
_1g_1filename_1to_1utf8_FUNC,
- _1g_1free_FUNC,
_1g_1get_1current_1time_FUNC,
_1g_1getenv_FUNC,
_1g_1hash_1table_1get_1values_FUNC,
@@ -1263,7 +1260,6 @@ typedef enum {
_1g_1object_1set__J_3BZJ_FUNC,
_1g_1object_1set__J_3B_3BJ_FUNC,
_1g_1object_1set_1qdata_FUNC,
- _1g_1object_1unref_FUNC,
_1g_1quark_1from_1string_FUNC,
_1g_1set_1prgname_FUNC,
_1g_1signal_1add_1emission_1hook_FUNC,
@@ -1309,7 +1305,6 @@ typedef enum {
_1g_1utf16_1offset_1to_1utf8_1offset_FUNC,
_1g_1utf16_1pointer_1to_1offset_FUNC,
_1g_1utf16_1strlen_FUNC,
- _1g_1utf16_1to_1utf8_FUNC,
_1g_1utf8_1offset_1to_1utf16_1offset_FUNC,
_1g_1utf8_1pointer_1to_1offset_FUNC,
_1g_1utf8_1strlen_FUNC,
@@ -1331,9 +1326,6 @@ typedef enum {
_1g_1variant_1get_1uint64_FUNC,
_1g_1variant_1is_1of_1type_FUNC,
_1g_1variant_1n_1children_FUNC,
- _1g_1variant_1new___3BZ_3B_FUNC,
- _1g_1variant_1new___3B_3B_FUNC,
- _1g_1variant_1new___3B_3B_3B_FUNC,
_1g_1variant_1new_1boolean_FUNC,
_1g_1variant_1new_1byte_FUNC,
_1g_1variant_1new_1double_FUNC,
@@ -1452,8 +1444,13 @@ typedef enum {
_1swt_1fixed_1resize_FUNC,
_1swt_1fixed_1restack_FUNC,
_1ubuntu_1menu_1proxy_1get_FUNC,
+ g_1dbus_1proxy_1call_FUNC,
+ g_1dbus_1proxy_1call_1sync_FUNC,
+ g_1free_FUNC,
g_1main_1context_1wakeup_FUNC,
+ g_1object_1unref_FUNC,
g_1strdup_FUNC,
+ g_1utf16_1to_1utf8_FUNC,
g_1value_1get_1double_FUNC,
g_1value_1get_1float_FUNC,
g_1value_1get_1int_FUNC,
@@ -1464,6 +1461,9 @@ typedef enum {
g_1value_1set_1int_FUNC,
g_1value_1set_1int64_FUNC,
g_1value_1unset_FUNC,
+ g_1variant_1new___3BZ_3B_FUNC,
+ g_1variant_1new___3B_3B_FUNC,
+ g_1variant_1new___3B_3B_3B_FUNC,
imContextLast_FUNC,
imContextNewProc_1CALLBACK_FUNC,
localeconv_1decimal_1point_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
index 213b7d8e70..a6f45d5a87 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
@@ -1731,15 +1731,8 @@ public static final long g_filename_from_uri(long uri, long [] hostname, long []
}
}
/** @param mem cast=(gpointer) */
-public static final native void _g_free(long mem);
-public static final void g_free(long mem) {
- lock.lock();
- try {
- _g_free(mem);
- } finally {
- lock.unlock();
- }
-}
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native void g_free(long mem);
/**
* @param variable cast=(const gchar *),flags=no_out
*/
@@ -2184,16 +2177,8 @@ public static final void g_object_set_qdata(long object, int quark, long data) {
}
}
/** @param object cast=(gpointer) */
-public static final native void _g_object_unref(long object);
-public static final void g_object_unref(long object) {
- lock.lock();
- try {
- _g_object_unref(object);
- } finally {
- lock.unlock();
- }
-}
-
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native void g_object_unref(long object);
/**
* @param data cast=(gconstpointer)
@@ -2706,15 +2691,8 @@ public static final long g_type_register_static (long parent_type, byte[] type_n
* @param items_written cast=(glong *),flags=critical
* @param error cast=(GError **),flags=critical
*/
-public static final native long _g_utf16_to_utf8(char[] str, long len, long [] items_read, long [] items_written, long [] error);
-public static final long g_utf16_to_utf8(char[] str, long len, long [] items_read, long [] items_written, long [] error) {
- lock.lock();
- try {
- return _g_utf16_to_utf8(str, len, items_read, items_written, error);
- } finally {
- lock.unlock();
- }
-}
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native long g_utf16_to_utf8(char[] str, long len, long [] items_read, long [] items_written, long [] error);
/**
* @param str cast=(const gchar *)
* @param pos cast=(const gchar *)
@@ -4229,15 +4207,8 @@ public static final long g_dbus_proxy_new_for_bus_sync (int bus_type, int flags,
* @param error cast=(GError **)
* @category gdbus
*/
-public static final native long _g_dbus_proxy_call_sync (long proxy, byte[] method_name, long parameters, int flags, int timeout_msec, long cancellable, long [] error);
-public static final long g_dbus_proxy_call_sync (long proxy, byte[] method_name, long parameters, int flags, int timeout_msec, long cancellable, long [] error) {
- lock.lock();
- try {
- return _g_dbus_proxy_call_sync (proxy, method_name, parameters, flags, timeout_msec, cancellable, error);
- } finally {
- lock.unlock();
- }
-}
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native long g_dbus_proxy_call_sync (long proxy, byte[] method_name, long parameters, int flags, int timeout_msec, long cancellable, long [] error);
/**
* @param proxy cast=(GDBusProxy *)
@@ -4248,15 +4219,8 @@ public static final long g_dbus_proxy_call_sync (long proxy, byte[] method_name,
* @param error cast=(GError **)
* @category gdbus
*/
-public static final native void _g_dbus_proxy_call (long proxy, byte[] method_name, long parameters, int flags, int timeout_msec, long cancellable, long callback, long [] error);
-public static final void g_dbus_proxy_call (long proxy, byte[] method_name, long parameters, int flags, int timeout_msec, long cancellable, long callback, long [] error) {
- lock.lock();
- try {
- _g_dbus_proxy_call (proxy, method_name, parameters, flags, timeout_msec, cancellable, callback, error);
- } finally {
- lock.unlock();
- }
-}
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native void g_dbus_proxy_call (long proxy, byte[] method_name, long parameters, int flags, int timeout_msec, long cancellable, long callback, long [] error);
/**
* @param proxy cast=(GDBusProxy *)
@@ -4475,16 +4439,8 @@ public static final void g_variant_builder_unref (long builder) {
* @param arg0 cast=(const gchar *),flags=no_out
* @category gdbus
*/
-public static final native long _g_variant_new (byte[] format_string, byte[] arg0);
-/** @category gdbus */
-public static final long g_variant_new (byte[] format_string, byte[] arg0) {
- lock.lock();
- try {
- return _g_variant_new(format_string, arg0);
- } finally {
- lock.unlock();
- }
-}
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native long g_variant_new (byte[] format_string, byte[] arg0);
/**
* @param format_string cast=(const gchar *),flags=no_out
@@ -4492,16 +4448,8 @@ public static final long g_variant_new (byte[] format_string, byte[] arg0) {
* @param arg1 cast=(const gchar *),flags=no_out
* @category gdbus
*/
-public static final native long _g_variant_new (byte[] format_string, boolean arg0, byte[] arg1);
-/** @category gdbus */
-public static final long g_variant_new (byte[] format_string, boolean arg0, byte[] arg1) {
- lock.lock();
- try {
- return _g_variant_new(format_string, arg0, arg1);
- } finally {
- lock.unlock();
- }
-}
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native long g_variant_new (byte[] format_string, boolean arg0, byte[] arg1);
/**
* @param format_string cast=(const gchar *),flags=no_out
@@ -4509,16 +4457,8 @@ public static final long g_variant_new (byte[] format_string, boolean arg0, byte
* @param arg1 cast=(const gchar *),flags=no_out
* @category gdbus
*/
-public static final native long _g_variant_new (byte[] format_string, byte[] arg0, byte[] arg1);
-/** @category gdbus */
-public static final long g_variant_new (byte[] format_string, byte[] arg0, byte[] arg1) {
- lock.lock();
- try {
- return _g_variant_new(format_string, arg0, arg1);
- } finally {
- lock.unlock();
- }
-}
+// NOTE: Lock is not used, see Bug 546743 and Bug 547093
+public static final native long g_variant_new (byte[] format_string, byte[] arg0, byte[] arg1);
/**
* @param intval cast=(gint32)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SessionManagerDBus.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SessionManagerDBus.java
index 14ae1825f0..44c5f3ea10 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SessionManagerDBus.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SessionManagerDBus.java
@@ -52,8 +52,47 @@ public class SessionManagerDBus {
void stop();
}
+ private static class ShutdownHook extends Thread {
+ private SessionManagerDBus parent;
+
+ public ShutdownHook(SessionManagerDBus parent) {
+ this.parent = parent;
+ }
+
+ public void run() {
+ parent.stop();
+ }
+
+ public void install() {
+ try {
+ Runtime.getRuntime().addShutdownHook(this);
+ } catch (IllegalArgumentException ex) {
+ // Shouldn't happen
+ ex.printStackTrace();
+ } catch (IllegalStateException ex) {
+ // Shouldn't happen
+ ex.printStackTrace();
+ } catch (SecurityException ex) {
+ // That's pity, but not too much of a problem.
+ }
+ }
+
+ public void remove() {
+ try {
+ Runtime.getRuntime().removeShutdownHook(this);
+ } catch (IllegalStateException ex) {
+ // JVM is already in the process of shutting down.
+ // That's expected when called from shutdown hook.
+ } catch (SecurityException ex) {
+ // Shouldn't happen if 'addShutdownHook' worked.
+ ex.printStackTrace();
+ }
+ }
+ }
+
private ArrayList<IListener> listeners = new ArrayList<IListener>();
private Callback g_signal_callback;
+ private ShutdownHook shutdownHook = new ShutdownHook(this);
private long sessionManagerProxy;
private long clientProxy;
private String clientObjectPath;
@@ -61,6 +100,15 @@ public class SessionManagerDBus {
private static int dbusTimeoutMsec = 10000;
+ /**
+ * 1) Prevents old answers to new signals. For example, if
+ * signal's handler asks user, it can stay for a while and when
+ * it's closed it could be the other signal already.
+ * 2) Makes sure answer is given on System.exit()
+ */
+ private long endSessionResponseCounter = 1;
+ private long endSessionResponseWanted = 0;
+
public SessionManagerDBus() {
// Allow to disable session manager, for example in case it conflicts with
// session manager connection implemented in application itself.
@@ -98,6 +146,11 @@ public class SessionManagerDBus {
return false;
}
+ // If application uses System.exit() while processing 'EndSession' signal
+ // then GNOME session can get stuck, see Bug 547093. The workaround
+ // is to install java shutdown hook that will still call .stop().
+ shutdownHook.install();
+
return true;
}
@@ -108,8 +161,18 @@ public class SessionManagerDBus {
* when client's process ends, so it's not a big deal if this is not
* called at all. See comments for this class to find 'dbus-send'
* commands to verify that.
+ *
+ * 'synchronized' guards against the rare possible case where some
+ * thread calls System.exit() while main thread is in Display.dispose()
+ * and both main thread and my 'ShutdownHook' try to run .stop().
*/
- private void stop() {
+ private synchronized void stop() {
+ if (endSessionResponseWanted != 0) {
+ // Happens when application exits with System.exit()
+ // while still in 'QueryEndSession' or 'EndSession'
+ sendEndSessionResponse(true, "", endSessionResponseWanted);
+ }
+
if ((sessionManagerProxy != 0) && (clientObjectPath != null)) {
long args = OS.g_variant_new(
Converter.javaStringToCString("(o)"), //$NON-NLS-1$
@@ -148,9 +211,27 @@ public class SessionManagerDBus {
g_signal_callback.dispose();
g_signal_callback = null;
}
+
+ shutdownHook.remove();
+ }
+
+ private long wantEndSessionResponse() {
+ long responseID = endSessionResponseCounter;
+ endSessionResponseCounter++;
+ endSessionResponseWanted = responseID;
+ return responseID;
}
- private void sendEndSessionResponse(boolean is_ok, String reason) {
+ private void sendEndSessionResponse(boolean is_ok, String reason, long responseID) {
+ if (responseID != endSessionResponseWanted) {
+ // A new signal has arrived while response was being prepared.
+ // Old response is no longer expected.
+ return;
+ }
+
+ // Mark as replied
+ endSessionResponseWanted = 0;
+
long args = OS.g_variant_new(
Converter.javaStringToCString("(bs)"), //$NON-NLS-1$
is_ok,
@@ -174,7 +255,7 @@ public class SessionManagerDBus {
}
}
- private boolean isReadyToExit() {
+ private boolean queryReadyToExit() {
boolean isReady = true;
// Inform everyone even if someone is not ready.
@@ -186,6 +267,28 @@ public class SessionManagerDBus {
return isReady;
}
+ private void handleQueryEndSession() {
+ // Save current ID before potential recursion
+ long responseID = wantEndSessionResponse();
+
+ // This can block/recurse if handler asks user
+ boolean isReady = queryReadyToExit();
+
+ sendEndSessionResponse(isReady, "", responseID);
+ }
+
+ private void handleEndSession() {
+ // Save current ID before potential recursion
+ long responseID = wantEndSessionResponse();
+
+ // This can block/recurse if handler asks user
+ handleStop();
+
+ // Only respond after we've done, or session can end while we're still working.
+ // Even if we don't want the session to end, I don't think sending 'false' here can be of any help.
+ sendEndSessionResponse(true, "", responseID);
+ }
+
private void handleStop() {
for (int i = 0; i < listeners.size(); i++) {
IListener listener = listeners.get(i);
@@ -207,13 +310,10 @@ public class SessionManagerDBus {
switch (signalName) {
case "QueryEndSession": //$NON-NLS-1$
- sendEndSessionResponse(isReadyToExit(), "");
+ handleQueryEndSession();
break;
case "EndSession": //$NON-NLS-1$
- handleStop();
- // Only respond after we've done, or session can end while we're still working.
- // Even if we don't want the session to end, I don't think sending 'false' here can be of any help.
- sendEndSessionResponse(true, "");
+ handleEndSession();
break;
case "Stop":
handleStop();
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547093_LogoffStuck.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547093_LogoffStuck.java
new file mode 100644
index 0000000000..9effebffa8
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug547093_LogoffStuck.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Syntevo and others. All rights reserved.
+ * The contents of this file are made available under the terms
+ * of the GNU Lesser General Public License (LGPL) Version 2.1 that
+ * accompanies this distribution (lgpl-v21.txt). The LGPL is also
+ * available at http://www.gnu.org/licenses/lgpl.html. If the version
+ * of the LGPL at http://www.gnu.org is different to the version of
+ * the LGPL accompanying this distribution and there is any conflict
+ * between the two license versions, the terms of the LGPL accompanying
+ * this distribution shall govern.
+ *
+ * Contributors:
+ * Syntevo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+public class Bug547093_LogoffStuck {
+ public static void main (String [] args) {
+ Display display = new Display ();
+
+ Shell shell = new Shell (display);
+ shell.setLayout(new FillLayout());
+ shell.setSize(300, 200);
+
+ display.addListener(SWT.Dispose, event -> {
+ /*
+ * System.exit() prevents org.eclipse.swt.internal.SessionManagerDBus
+ * from sending reply to session manager and it gets stuck waiting for
+ * that reply.
+ */
+ System.exit(0);
+ });
+
+ final Label label = new Label(shell, SWT.WRAP | SWT.CENTER);
+ label.setText("\n\n\nWhen you logoff, GNOME session manager will get stuck for 90 seconds");
+
+ // Test for deadlock with shutdown hook on regular closing
+ shell.addListener(SWT.Close, event -> {
+ System.exit(0);
+ });
+
+ shell.open ();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch ()) display.sleep ();
+ }
+
+ display.dispose ();
+ }
+}

Back to the top