Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandr Miloslavskiy2019-04-23 03:12:03 -0400
committerAlexandr Miloslavskiy2019-04-24 09:35:07 -0400
commit3d47beb6a71aa3e72762c9a55af531c0aedab8df (patch)
treeca03ba647a4141272d07d07af030d120a0b54861
parent6e658162caecbb8cd6711a48f60c4ed46c1b2615 (diff)
downloadeclipse.platform.swt-3d47beb6a71aa3e72762c9a55af531c0aedab8df.tar.gz
eclipse.platform.swt-3d47beb6a71aa3e72762c9a55af531c0aedab8df.tar.xz
eclipse.platform.swt-3d47beb6a71aa3e72762c9a55af531c0aedab8df.zip
Bug 531634 - [GTK] Linux: Handle logoff / shutdown events from session manager
Fix 1 ----- Previously, SWT applications terminated unexpectedly on session end (logoff / shutdown) and didn't have a chance to perform on-exit actions, such as saving current settings. This patch fixes it, bringing Linux in line with Windows and macOS. SWT applications will now: 1) Receive 'SWT.Close' event for their 'Display'. Similar to Windows and macOS, this now allows to set 'Event.doit' to 'false', hinting the OS that application is not ready to close. Linux often ignores this hint, though. I think handling this properly would require inhibitors which are not yet covered by this patch. 2) Force 'Display.dispose()' when 'EndSession' is received This allows applications to use all forms of on-exit cleanup, such as * Listening to 'SWT.Dispose' * Running code after 'while (!display.isDisposed())' * Installing Java shutdown hooks (because a typical application will exit its 'main()' after display is disposed) Some system properties are available for customization, see code in 'org.eclipse.swt.internal.SessionManagerDBus' Fix 2 ----- Noticed and fixed a memory leak in 'WebkitGDBusinvokeReturnValueExtensionIdentifier'. Fix 3 ----- Moved test snippets to correct folder Change-Id: If968fc4b86cc0b6de192ef3ef4319ca96967cd22 Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c122
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h8
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java119
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SessionManagerDBus.java480
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java27
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug481485_ButtonLabelPaintListener.java (renamed from tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug481485_ButtonLabelPaintListener.java)0
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug531634_LogoffListener.java55
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java (renamed from tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java)0
10 files changed, 819 insertions, 1 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 b1acaff1d0..16ae5c75c4 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
@@ -14766,6 +14766,18 @@ fail:
}
#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)
+{
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1dbus_1proxy_1get_1name_1owner_FUNC);
+ rc = (jlong)g_dbus_proxy_get_name_owner((GDBusProxy *)arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1dbus_1proxy_1get_1name_1owner_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1g_1dbus_1proxy_1new_1for_1bus_1sync
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1dbus_1proxy_1new_1for_1bus_1sync)
(JNIEnv *env, jclass that, jint arg0, jint arg1, jlong arg2, jbyteArray arg3, jbyteArray arg4, jbyteArray arg5, jlong arg6, jlongArray arg7)
@@ -15028,6 +15040,22 @@ JNIEXPORT void JNICALL OS_NATIVE(_1g_1get_1current_1time)
}
#endif
+#ifndef NO__1g_1getenv
+JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1getenv)
+ (JNIEnv *env, jclass that, jbyteArray arg0)
+{
+ jbyte *lparg0=NULL;
+ jlong rc = 0;
+ OS_NATIVE_ENTER(env, that, _1g_1getenv_FUNC);
+ if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
+ rc = (jlong)g_getenv((const gchar *)lparg0);
+fail:
+ if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
+ OS_NATIVE_EXIT(env, that, _1g_1getenv_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1g_1hash_1table_1get_1values
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1hash_1table_1get_1values)
(JNIEnv *env, jclass that, jlong arg0)
@@ -16127,6 +16155,20 @@ fail:
}
#endif
+#ifndef NO__1g_1unsetenv
+JNIEXPORT void JNICALL OS_NATIVE(_1g_1unsetenv)
+ (JNIEnv *env, jclass that, jbyteArray arg0)
+{
+ jbyte *lparg0=NULL;
+ OS_NATIVE_ENTER(env, that, _1g_1unsetenv_FUNC);
+ if (arg0) if ((lparg0 = (*env)->GetByteArrayElements(env, arg0, NULL)) == NULL) goto fail;
+ g_unsetenv((const gchar *)lparg0);
+fail:
+ if (arg0 && lparg0) (*env)->ReleaseByteArrayElements(env, arg0, lparg0, JNI_ABORT);
+ OS_NATIVE_EXIT(env, that, _1g_1unsetenv_FUNC);
+}
+#endif
+
#ifndef NO__1g_1utf16_1offset_1to_1pointer
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1utf16_1offset_1to_1pointer)
(JNIEnv *env, jclass that, jlong arg0, jlong arg1)
@@ -16479,6 +16521,66 @@ 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)
@@ -16571,6 +16673,16 @@ JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1new_1uint64)
}
#endif
+#ifndef NO__1g_1variant_1type_1free
+JNIEXPORT void JNICALL OS_NATIVE(_1g_1variant_1type_1free)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1type_1free_FUNC);
+ g_variant_type_free((GVariantType *)arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1type_1free_FUNC);
+}
+#endif
+
#ifndef NO__1g_1variant_1type_1new
JNIEXPORT jlong JNICALL OS_NATIVE(_1g_1variant_1type_1new)
(JNIEnv *env, jclass that, jbyteArray arg0)
@@ -16587,6 +16699,16 @@ fail:
}
#endif
+#ifndef NO__1g_1variant_1unref
+JNIEXPORT void JNICALL OS_NATIVE(_1g_1variant_1unref)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ OS_NATIVE_ENTER(env, that, _1g_1variant_1unref_FUNC);
+ g_variant_unref((GVariant *)arg0);
+ OS_NATIVE_EXIT(env, that, _1g_1variant_1unref_FUNC);
+}
+#endif
+
#ifndef NO__1getpid
JNIEXPORT jint JNICALL OS_NATIVE(_1getpid)
(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 ef46e89be3..40806b67d5 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
@@ -1223,6 +1223,7 @@ char * OS_nativeFunctionNames[] = {
"_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",
"_1g_1error_1get_1message",
@@ -1240,6 +1241,7 @@ char * OS_nativeFunctionNames[] = {
"_1g_1filename_1to_1utf8",
"_1g_1free",
"_1g_1get_1current_1time",
+ "_1g_1getenv",
"_1g_1hash_1table_1get_1values",
"_1g_1icon_1new_1for_1string",
"_1g_1icon_1to_1string",
@@ -1326,6 +1328,7 @@ char * OS_nativeFunctionNames[] = {
"_1g_1type_1parent",
"_1g_1type_1query",
"_1g_1type_1register_1static",
+ "_1g_1unsetenv",
"_1g_1utf16_1offset_1to_1pointer",
"_1g_1utf16_1offset_1to_1utf8_1offset",
"_1g_1utf16_1pointer_1to_1offset",
@@ -1352,6 +1355,9 @@ 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",
@@ -1359,7 +1365,9 @@ char * OS_nativeFunctionNames[] = {
"_1g_1variant_1new_1string",
"_1g_1variant_1new_1tuple",
"_1g_1variant_1new_1uint64",
+ "_1g_1variant_1type_1free",
"_1g_1variant_1type_1new",
+ "_1g_1variant_1unref",
"_1getpid",
"_1glib_1major_1version",
"_1glib_1micro_1version",
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 7e6d144d0b..935e7d2522 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
@@ -1197,6 +1197,7 @@ typedef enum {
_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,
_1g_1error_1get_1message_FUNC,
@@ -1214,6 +1215,7 @@ typedef enum {
_1g_1filename_1to_1utf8_FUNC,
_1g_1free_FUNC,
_1g_1get_1current_1time_FUNC,
+ _1g_1getenv_FUNC,
_1g_1hash_1table_1get_1values_FUNC,
_1g_1icon_1new_1for_1string_FUNC,
_1g_1icon_1to_1string_FUNC,
@@ -1300,6 +1302,7 @@ typedef enum {
_1g_1type_1parent_FUNC,
_1g_1type_1query_FUNC,
_1g_1type_1register_1static_FUNC,
+ _1g_1unsetenv_FUNC,
_1g_1utf16_1offset_1to_1pointer_FUNC,
_1g_1utf16_1offset_1to_1utf8_1offset_FUNC,
_1g_1utf16_1pointer_1to_1offset_FUNC,
@@ -1326,6 +1329,9 @@ 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,
@@ -1333,7 +1339,9 @@ typedef enum {
_1g_1variant_1new_1string_FUNC,
_1g_1variant_1new_1tuple_FUNC,
_1g_1variant_1new_1uint64_FUNC,
+ _1g_1variant_1type_1free_FUNC,
_1g_1variant_1type_1new_FUNC,
+ _1g_1variant_1unref_FUNC,
_1getpid_FUNC,
_1glib_1major_1version_FUNC,
_1glib_1micro_1version_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 6e605618d6..213b7d8e70 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
@@ -1741,6 +1741,18 @@ public static final void g_free(long mem) {
}
}
/**
+ * @param variable cast=(const gchar *),flags=no_out
+ */
+public static final native long _g_getenv(byte [] variable);
+public static final long g_getenv(byte [] variable) {
+ lock.lock();
+ try {
+ return _g_getenv(variable);
+ } finally {
+ lock.unlock();
+ }
+}
+/**
* @param table cast=(GHashTable *)
*/
public static final native long _g_hash_table_get_values(long table);
@@ -2791,7 +2803,18 @@ public static final long g_value_peek_pointer (long value) {
lock.unlock();
}
}
-
+/**
+ * @param variable cast=(const gchar *),flags=no_out
+ */
+public static final native void _g_unsetenv(byte [] variable);
+public static final void g_unsetenv(byte [] variable) {
+ lock.lock();
+ try {
+ _g_unsetenv(variable);
+ } finally {
+ lock.unlock();
+ }
+}
/** @method flags=const */
public static final native int _glib_major_version();
public static final int glib_major_version() {
@@ -4237,6 +4260,20 @@ public static final void g_dbus_proxy_call (long proxy, byte[] method_name, long
/**
* @param proxy cast=(GDBusProxy *)
+ * @category gdbus
+ */
+public static final native long _g_dbus_proxy_get_name_owner (long proxy);
+public static final long g_dbus_proxy_get_name_owner (long proxy) {
+ lock.lock();
+ try {
+ return _g_dbus_proxy_get_name_owner (proxy);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
+ * @param proxy cast=(GDBusProxy *)
* @param res cast=(GAsyncResult *)
* @param error cast=(GError **)
* @category gdbus
@@ -4374,6 +4411,21 @@ public static final void g_variant_builder_add_value (long builder, long value)
}
/**
+ * @param type cast=(GVariantType *)
+ * @category gdbus
+ */
+public static final native void _g_variant_type_free (long type);
+/** @category gdbus */
+public static final void g_variant_type_free (long type) {
+ lock.lock();
+ try {
+ _g_variant_type_free(type);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
* @param type cast=(const gchar *)
* @category gdbus
*/
@@ -4419,6 +4471,56 @@ public static final void g_variant_builder_unref (long builder) {
}
/**
+ * @param format_string cast=(const gchar *),flags=no_out
+ * @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();
+ }
+}
+
+/**
+ * @param format_string cast=(const gchar *),flags=no_out
+ * @param arg0 cast=(gboolean)
+ * @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();
+ }
+}
+
+/**
+ * @param format_string cast=(const gchar *),flags=no_out
+ * @param arg0 cast=(const gchar *),flags=no_out
+ * @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();
+ }
+}
+
+/**
* @param intval cast=(gint32)
* @category gdbus
*/
@@ -4692,6 +4794,21 @@ public static final long g_variant_new_string (byte[] string) {
}
/**
+ * @param value cast=(GVariant *)
+ * @category gdbus
+ */
+public static final native void _g_variant_unref (long value);
+/** @category gdbus */
+public static final void g_variant_unref (long value) {
+ lock.lock();
+ try {
+ _g_variant_unref (value);
+ } finally {
+ lock.unlock();
+ }
+}
+
+/**
* @param object cast=(GObject *)
*/
public static final native long _g_object_ref_sink(long object);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java
index 1d2d9edae9..64aa8a5bcc 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT WebKit/gtk/org/eclipse/swt/browser/WebkitGDBus.java
@@ -380,6 +380,7 @@ class WebkitGDBus {
long finalGVariant = OS.g_variant_new_tuple(variants, 1);
OS.g_dbus_method_invocation_return_value(invocation, finalGVariant);
OS.g_variant_builder_unref(builder);
+ OS.g_variant_type_free(type);
return;
}
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
new file mode 100644
index 0000000000..02b67d4fd0
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/internal/SessionManagerDBus.java
@@ -0,0 +1,480 @@
+/*******************************************************************************
+ * 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.internal;
+
+import org.eclipse.swt.internal.gtk.OS;
+
+import java.util.ArrayList;
+
+/**
+ * Communicates with session manager to receive logoff/shutdown events.
+ *
+ * GTK also has an implementation (see gtk_application_impl_dbus_startup)
+ * However, it requires GtkApplication, and SWT doesn't use that.
+ *
+ * Current session manager clients can be seen in:
+ * dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.GetClients
+ *
+ * If you know clientObjectPath, you can send Stop signal with:
+ * dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager/ClientXX org.gnome.SessionManager.Client.Stop
+ */
+public class SessionManagerDBus {
+ public interface IListener {
+ /**
+ * Are you ready to exit?
+ *
+ * Time limit imposed by session manager is 1 second.
+ * Final cleanup should happen in stop().
+ * @return false to hint that you're not ready. Session manager can ignore the hint.
+ */
+ boolean isReadyToExit();
+
+ /**
+ * Perform final cleanup here.
+ *
+ * Please note that time limit imposed by session manager is 10 seconds.
+ */
+ 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.
+ // Client will stay registered, contributing to clutter a little bit.
+ }
+ }
+
+ public void remove() {
+ try {
+ Runtime.getRuntime().removeShutdownHook(this);
+ } catch (IllegalStateException ex) {
+ // The virtual machine is already in the process of shutting down.
+ // That's expected.
+ } 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;
+ private boolean isGnome;
+
+ private static int dbusTimeoutMsec = 10000;
+
+ public SessionManagerDBus() {
+ // Allow to disable session manager, for example in case it conflicts with
+ // session manager connection implemented in application itself.
+ boolean isDisabled = System.getProperty("org.eclipse.swt.internal.SessionManagerDBus.disable") != null;
+ if (isDisabled) return;
+
+ start();
+ }
+
+ /**
+ * Subscribes display for session manager events.
+ *
+ * Display will receive SWT.Close and will be able to hint that the session should not end.
+ * Please note that time limit imposed by session manager is 1 second.
+ * Final cleanup should happen at Display.dispose().
+ *
+ * Display will be disposed before session ends, allowing final cleanup to happen.
+ * Please note that time limit imposed by session manager is 10 seconds.
+ */
+ public void addListener(IListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(IListener listener) {
+ listeners.remove(listener);
+ }
+
+ private boolean start() {
+ if (!connectSessionManager() || !registerClient() || !connectClientSignal()) {
+ stop();
+ return false;
+ }
+
+ // Both XFCE and Gnome will automatically unregister client on exit.
+ // However, to be on the correct side, we should also do it.
+ // Shutdown hook is used, because there's no other exit callback in SWT.
+ // Display.dispose() isn't good because there could be many displays.
+ // Also, in theory Displays can be created and disposed multiple times.
+ shutdownHook.install();
+
+ return true;
+ }
+
+ private void stop() {
+ if ((sessionManagerProxy != 0) && (clientObjectPath != null)) {
+ long args = OS.g_variant_new(
+ Converter.javaStringToCString("(o)"), //$NON-NLS-1$
+ Converter.javaStringToCString(clientObjectPath));
+
+ long [] error = new long [1];
+ OS.g_dbus_proxy_call_sync(
+ sessionManagerProxy,
+ Converter.javaStringToCString("UnregisterClient"), //$NON-NLS-1$
+ args,
+ OS.G_DBUS_CALL_FLAGS_NONE,
+ dbusTimeoutMsec,
+ 0,
+ error);
+
+ if (error[0] != 0) {
+ System.err.format(
+ "SWT SessionManagerDBus: Failed to UnregisterClient: %s%n",
+ extractFreeGError(error[0]));
+ }
+
+ clientObjectPath = null;
+ }
+
+ if (clientProxy != 0) {
+ OS.g_object_unref(clientProxy);
+ clientProxy = 0;
+ }
+
+ if (sessionManagerProxy != 0) {
+ OS.g_object_unref(sessionManagerProxy);
+ sessionManagerProxy = 0;
+ }
+
+ if (g_signal_callback != null) {
+ g_signal_callback.dispose();
+ g_signal_callback = null;
+ }
+
+ shutdownHook.remove();
+ }
+
+ private void sendEndSessionResponse(boolean is_ok, String reason) {
+ long args = OS.g_variant_new(
+ Converter.javaStringToCString("(bs)"), //$NON-NLS-1$
+ is_ok,
+ Converter.javaStringToCString(reason));
+
+ long [] error = new long [1];
+ OS.g_dbus_proxy_call(
+ clientProxy,
+ Converter.javaStringToCString("EndSessionResponse"), //$NON-NLS-1$
+ args,
+ OS.G_DBUS_CALL_FLAGS_NONE,
+ dbusTimeoutMsec,
+ 0,
+ 0,
+ error);
+
+ if (error[0] != 0) {
+ System.err.format(
+ "SWT SessionManagerDBus: Failed to EndSessionResponse: %s%n",
+ extractFreeGError(error[0]));
+ }
+ }
+
+ private boolean isReadyToExit() {
+ boolean isReady = true;
+
+ // Inform everyone even if someone is not ready.
+ for (int i = 0; i < listeners.size(); i++) {
+ IListener listener = listeners.get(i);
+ isReady = isReady && listener.isReadyToExit();
+ }
+
+ return isReady;
+ }
+
+ private void handleStop() {
+ for (int i = 0; i < listeners.size(); i++) {
+ IListener listener = listeners.get(i);
+ listener.stop();
+ }
+ }
+
+ /**
+ * Receives events from session manager.
+ *
+ * Docs: https://developer.gnome.org/gio/stable/GDBusProxy.html#GDBusProxy-g-signal
+ * NOTE: Will be called through native callback.
+ * @see this.g_signal_callback
+ * @return Error string in case of error, null if successful.
+ */
+ @SuppressWarnings("unused")
+ private long g_signal_handler(long proxy, long sender_name, long signal_name, long parameters, long user_data) {
+ String signalName = Converter.cCharPtrToJavaString(signal_name, false);
+
+ switch (signalName) {
+ case "QueryEndSession": //$NON-NLS-1$
+ sendEndSessionResponse(isReadyToExit(), "");
+ 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, "");
+ break;
+ case "Stop":
+ handleStop();
+ break;
+ }
+
+ // DBus expects 'void', but to make it easier to use with 'Callback' I return 'long'.
+ return 0;
+ }
+
+ private static String extractVariantTupleS(long variant) {
+ long childVariant = OS.g_variant_get_child_value(variant, 0);
+ long childString = OS.g_variant_get_string(childVariant, null);
+
+ String result = Converter.cCharPtrToJavaString(childString, false);
+
+ OS.g_variant_unref(childVariant);
+ return result;
+ }
+
+ private static String extractFreeGError(long errorPtr) {
+ long errorMessageC = OS.g_error_get_message(errorPtr);
+ String errorMessageStr = Converter.cCharPtrToJavaString(errorMessageC, false);
+ OS.g_error_free(errorPtr);
+ return errorMessageStr;
+ }
+
+ /**
+ * Creates a connection to the session manager.
+ *
+ * Saves result to member variable when successful.
+ * @return Error string in case of error, null if successful.
+ */
+ private String connectSessionManager(String dbusName, String objectPath, String interfaceName) {
+ int sessionManagerFlags =
+ OS.G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
+ OS.G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
+ OS.G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS;
+
+ long [] error = new long [1];
+ long proxy = OS.g_dbus_proxy_new_for_bus_sync(
+ OS.G_BUS_TYPE_SESSION,
+ sessionManagerFlags,
+ 0,
+ Converter.javaStringToCString(dbusName),
+ Converter.javaStringToCString(objectPath),
+ Converter.javaStringToCString(interfaceName),
+ 0,
+ error);
+
+ // Proxy is usually created even for non-existent service names.
+ if (proxy == 0) return extractFreeGError(error[0]);
+
+ // Is the service actually present?
+ long owner = OS.g_dbus_proxy_get_name_owner(proxy);
+ if (owner == 0) {
+ OS.g_object_unref(proxy);
+ return "Service not present";
+ }
+ OS.g_free(owner);
+
+ // Success
+ sessionManagerProxy = proxy;
+ return null;
+ }
+
+ private boolean connectSessionManager() {
+ String errorGnome = connectSessionManager(
+ "org.gnome.SessionManager", //$NON-NLS-1$
+ "/org/gnome/SessionManager", //$NON-NLS-1$
+ "org.gnome.SessionManager"); //$NON-NLS-1$
+
+ if (errorGnome == null) {
+ isGnome = true;
+ return true;
+ }
+
+ String errorXCFE = connectSessionManager(
+ "org.xfce.SessionManager", //$NON-NLS-1$
+ "/org/xfce/SessionManager", //$NON-NLS-1$
+ "org.xfce.Session.Manager"); //$NON-NLS-1$
+
+ if (errorXCFE == null) {
+ isGnome = false;
+ return true;
+ }
+
+ System.err.format(
+ "SWT SessionManagerDBus: Failed to connect to SessionManager (gnome: %s, xcfe: %s)%n",
+ errorGnome,
+ errorXCFE);
+
+ return false;
+ }
+
+ /**
+ * Gets the value of 'DESKTOP_AUTOSTART_ID'.
+ *
+ * This environment variable is set by session manager if the
+ * application was auto started (because it is configured to run
+ * automatically for every session). The variable helps session
+ * manager to match autostart settings with actual applications.
+ *
+ * For applications that were not started automatically, the
+ * variable is expected to be absent.
+ *
+ * Once used, 'DESKTOP_AUTOSTART_ID' must not leak into child
+ * processes, or they will fail to 'RegisterClient'.
+ */
+ private String claimDesktopAutostartID() {
+ byte[] DESKTOP_AUTOSTART_ID = Converter.javaStringToCString("DESKTOP_AUTOSTART_ID"); //$NON-NLS-1$
+
+ // NOTE: the returned pointer is not valid after g_unsetenv()
+ long valueC = OS.g_getenv(DESKTOP_AUTOSTART_ID);
+ if (valueC == 0) return null;
+ String result = Converter.cCharPtrToJavaString(valueC, false);
+
+ // Unset value, so it doesn't leak into child processes
+ OS.g_unsetenv(DESKTOP_AUTOSTART_ID);
+
+ return result;
+ }
+
+ /**
+ * Issues 'RegisterClient' dbus request to register with session manager.
+ *
+ * Saves result to member variable when successful.
+ * @return Error string in case of error, null if successful.
+ */
+ private String registerClient(String appID, String clientStartupID) {
+ long args = OS.g_variant_new(
+ Converter.javaStringToCString("(ss)"), //$NON-NLS-1$
+ Converter.javaStringToCString(appID),
+ Converter.javaStringToCString(clientStartupID));
+
+ long [] error = new long [1];
+ long clientInfo = OS.g_dbus_proxy_call_sync(
+ sessionManagerProxy,
+ Converter.javaStringToCString("RegisterClient"), //$NON-NLS-1$
+ args,
+ OS.G_DBUS_CALL_FLAGS_NONE,
+ dbusTimeoutMsec,
+ 0,
+ error);
+
+ if (clientInfo == 0) return extractFreeGError(error[0]);
+
+ // Success
+ clientObjectPath = extractVariantTupleS(clientInfo);
+ OS.g_variant_unref(clientInfo);
+ return null;
+ }
+
+ private boolean registerClient() {
+ // This ID doesn't matter much, at least according to what I know.
+ // Still, I decided to make it customizable for those who love identity.
+ String appID = System.getProperty("org.eclipse.swt.internal.SessionManagerDBus.appID"); //$NON-NLS-1$
+ if (appID == null) appID = "org.eclipse.swt.Application"; //$NON-NLS-1$
+
+ // Applications are expected to register using value of
+ // 'DESKTOP_AUTOSTART_ID' environment if it's present.
+ String desktopAutostartID = claimDesktopAutostartID();
+ if (desktopAutostartID != null) {
+ String errorText = registerClient(appID, desktopAutostartID);
+ if (errorText == null) return true;
+
+ // Bugged launchers use their 'DESKTOP_AUTOSTART_ID', but forget to unset it.
+ // This leaks a value that can't be used.
+ // The workaround is to retry with empty ID below.
+ // This pretends that parent's bug is already fixed.
+ boolean parentLeakedID = errorText.startsWith("GDBus.Error:org.gnome.SessionManager.AlreadyRegistered:"); //$NON-NLS-1$
+ if (!parentLeakedID) return false;
+ }
+
+ // In absence of 'DESKTOP_AUTOSTART_ID' just use empty ID.
+ String errorText = registerClient(appID, "");
+ if (errorText == null) return true;
+
+ // On XFCE 'RegisterClient' is only available since 4.13.0.
+ // Don't print this error since it's expected.
+ if (!isGnome && errorText.startsWith("GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: ")) //$NON-NLS-1$
+ return false;
+
+ System.err.format(
+ "SWT SessionManagerDBus: Failed to RegisterClient: %s%n",
+ errorText);
+
+ return false;
+ }
+
+ private boolean connectClientSignal() {
+ String dbusName;
+ String interfaceName;
+ if (isGnome) {
+ dbusName = "org.gnome.SessionManager"; //$NON-NLS-1$
+ interfaceName = "org.gnome.SessionManager.ClientPrivate"; //$NON-NLS-1$
+ } else {
+ dbusName = "org.xfce.SessionManager"; //$NON-NLS-1$
+ interfaceName = "org.xfce.Session.Client"; //$NON-NLS-1$
+ }
+
+ long [] error = new long [1];
+ clientProxy = OS.g_dbus_proxy_new_for_bus_sync(
+ OS.G_BUS_TYPE_SESSION,
+ 0,
+ 0,
+ Converter.javaStringToCString(dbusName),
+ Converter.javaStringToCString(clientObjectPath),
+ Converter.javaStringToCString(interfaceName),
+ 0,
+ error);
+
+ if (clientProxy == 0) {
+ System.err.format(
+ "SWT SessionManagerDBus: Failed to connect to Client: %s%n",
+ extractFreeGError(error[0]));
+ return false;
+ }
+
+ // The rest of the code makes this key call possible
+ g_signal_callback = new Callback(this, "g_signal_handler", 5); //$NON-NLS-1$
+ OS.g_signal_connect(
+ clientProxy,
+ Converter.javaStringToCString("g-signal"), //$NON-NLS-1$
+ g_signal_callback.getAddress(),
+ 0);
+
+ return true;
+ }
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
index 506106abeb..5c7fd36499 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
@@ -192,6 +192,26 @@ public class Display extends Device {
Thread thread;
/* Display Shutdown */
+ private class SessionManagerListener implements SessionManagerDBus.IListener {
+ Display parent;
+
+ public SessionManagerListener(Display parent) {
+ this.parent = parent;
+ }
+
+ public boolean isReadyToExit() {
+ Event event = new Event ();
+ parent.sendEvent(SWT.Close, event);
+ return event.doit;
+ }
+
+ public void stop() {
+ parent.dispose();
+ }
+ }
+
+ static SessionManagerDBus sessionManagerDBus = new SessionManagerDBus();
+ SessionManagerListener sessionManagerListener;
Runnable [] disposeList;
/* Deferred Layout list */
@@ -3567,6 +3587,7 @@ protected void init () {
initializeSystemSettings ();
initializeWidgetTable ();
initializeWindowManager ();
+ initializeSessionManager ();
}
void initializeCallbacks () {
@@ -3960,6 +3981,11 @@ void initializeWindowManager () {
}
}
+void initializeSessionManager() {
+ sessionManagerListener = new SessionManagerListener(this);
+ sessionManagerDBus.addListener(sessionManagerListener);
+}
+
/**
* Invokes platform specific functionality to dispose a GC handle.
* <p>
@@ -4692,6 +4718,7 @@ protected void release () {
disposeList = null;
synchronizer.releaseSynchronizer ();
synchronizer = null;
+ sessionManagerDBus.removeListener(sessionManagerListener);
releaseDisplay ();
super.release ();
}
diff --git a/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug481485_ButtonLabelPaintListener.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug481485_ButtonLabelPaintListener.java
index a9800c9f9f..a9800c9f9f 100644
--- a/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug481485_ButtonLabelPaintListener.java
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug481485_ButtonLabelPaintListener.java
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug531634_LogoffListener.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug531634_LogoffListener.java
new file mode 100644
index 0000000000..8187df05c2
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug531634_LogoffListener.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.*;
+
+public class Bug531634_LogoffListener {
+ 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.Close, event -> {
+ MessageBox dialog = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES | SWT.NO);
+ dialog.setMessage("QueryEndSession received.\nGive 'ready' hint? Time limit to answer is 1 sec");
+ int answer = dialog.open();
+ event.doit = (SWT.YES == answer);
+ });
+
+ display.addListener(SWT.Dispose, event -> {
+ if (!shell.isDisposed()) {
+ MessageBox dialog = new MessageBox(shell, SWT.ICON_INFORMATION);
+ dialog.setMessage("EndSession received.\nI will exit when you close this box. Time limit is 10 sec.");
+ dialog.open();
+ }
+ });
+
+ final Label label = new Label(shell, SWT.WRAP | SWT.CENTER);
+ label.setText("\n\n\nWhen you logoff/shutdown, I will give you messages on 'QueryEndSession' and 'EndSession'");
+
+ shell.open ();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch ()) display.sleep ();
+ }
+
+ display.dispose ();
+ }
+}
diff --git a/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java
index c123889d75..c123889d75 100644
--- a/tests/org.eclipse.swt.tests.gtk/Bug Snippets/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug545587_TooltipColor.java

Back to the top