Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Williams2019-10-04 15:22:25 +0000
committerEric Williams2019-10-04 17:57:41 +0000
commitb611c641f66406730e0b9fd0ad5e6774606415bd (patch)
treeb864c419c252608c2de80eb1cf66c05f2a737bc8 /bundles/org.eclipse.swt
parentb1cdee636d9ff61b21473c8bdfa1f548a1130384 (diff)
downloadeclipse.platform.swt-b611c641f66406730e0b9fd0ad5e6774606415bd.tar.gz
eclipse.platform.swt-b611c641f66406730e0b9fd0ad5e6774606415bd.tar.xz
eclipse.platform.swt-b611c641f66406730e0b9fd0ad5e6774606415bd.zip
Bug 537896: [HiDPI][GTK] SWT to receive/handle DPI change notification from OS
Connect the first Shell for a given Display to the "notify::scale-factor" signal, in order to detect changes in DPI from GTK. Calculate whether the DPI has changed, and notify listeners to the SWT.ZoomChanged event. Tested on GTK3.24, Fedora 30, X11 and Wayland on Snippet373. No AllNonBrowser JUnit tests fail. Change-Id: I73623667386f447e2071c1beac46e3213fb2bda3 Signed-off-by: Eric Williams <ericwill@redhat.com>
Diffstat (limited to 'bundles/org.eclipse.swt')
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c12
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java13
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java1
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java3
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java54
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java12
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java30
9 files changed, 104 insertions, 23 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 df4e97d791..72435895eb 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
@@ -12371,6 +12371,18 @@ JNIEXPORT jboolean JNICALL GTK_NATIVE(_1gtk_1widget_1get_1realized)
}
#endif
+#ifndef NO__1gtk_1widget_1get_1scale_1factor
+JNIEXPORT jint JNICALL GTK_NATIVE(_1gtk_1widget_1get_1scale_1factor)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jint rc = 0;
+ GTK_NATIVE_ENTER(env, that, _1gtk_1widget_1get_1scale_1factor_FUNC);
+ rc = (jint)gtk_widget_get_scale_factor((GtkWidget *)arg0);
+ GTK_NATIVE_EXIT(env, that, _1gtk_1widget_1get_1scale_1factor_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1gtk_1widget_1get_1screen
JNIEXPORT jlong JNICALL GTK_NATIVE(_1gtk_1widget_1get_1screen)
(JNIEnv *env, jclass that, jlong arg0)
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 c72ea32f92..ae368db4a6 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
@@ -978,6 +978,7 @@ char * GTK_nativeFunctionNames[] = {
"_1gtk_1widget_1get_1preferred_1size",
"_1gtk_1widget_1get_1preferred_1width_1for_1height",
"_1gtk_1widget_1get_1realized",
+ "_1gtk_1widget_1get_1scale_1factor",
"_1gtk_1widget_1get_1screen",
"_1gtk_1widget_1get_1sensitive",
"_1gtk_1widget_1get_1size_1request",
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 77ffdee96d..395c9da3ba 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
@@ -976,6 +976,7 @@ typedef enum {
_1gtk_1widget_1get_1preferred_1size_FUNC,
_1gtk_1widget_1get_1preferred_1width_1for_1height_FUNC,
_1gtk_1widget_1get_1realized_FUNC,
+ _1gtk_1widget_1get_1scale_1factor_FUNC,
_1gtk_1widget_1get_1screen_FUNC,
_1gtk_1widget_1get_1sensitive_FUNC,
_1gtk_1widget_1get_1size_1request_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 500aafea2d..1050f0826c 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
@@ -514,6 +514,19 @@ public class GTK extends OS {
}
}
+ /**
+ * @param widget cast=(GtkWidget *)
+ */
+ public static final native int _gtk_widget_get_scale_factor(long widget);
+ public static final int gtk_widget_get_scale_factor(long widget) {
+ lock.lock();
+ try {
+ return _gtk_widget_get_scale_factor(widget);
+ } finally {
+ lock.unlock();
+ }
+ }
+
/** @param widget cast=(GtkWidget *) */
public static final native long _gtk_widget_get_name(long widget);
public static final long gtk_widget_get_name(long widget) {
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 8715917033..185509edf8 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
@@ -302,6 +302,7 @@ public class OS extends C {
public static final byte[] delete_range = ascii("delete-range");
public static final byte[] delete_text = ascii("delete-text");
public static final byte[] direction_changed = ascii("direction-changed");
+ public static final byte[] dpi_changed = ascii("notify::scale-factor");
public static final byte[] drag_begin = ascii("drag_begin");
public static final byte[] drag_data_delete = ascii("drag_data_delete");
public static final byte[] drag_data_get = ascii("drag_data_get");
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
index 110eded727..d18b020230 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/SWT.java
@@ -868,7 +868,8 @@ public class SWT {
* </p>
* <p>
* Note that this is a <em>HINT</em> and is not sent on platforms that do not
- * support dynamic DPI changes. This event is currently sent on Windows 10 only.
+ * support dynamic DPI changes. This event is currently sent on Windows 10 and GTK
+ * only.
* </p>
*
* @see org.eclipse.swt.widgets.Widget#addListener
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 a6b23977c4..b0547fa326 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
@@ -131,12 +131,12 @@ public class Display extends Device {
long snapshotDrawProc, changeValueProc;
long keyPressReleaseProc, focusProc, enterMotionScrollProc, leaveProc;
long gesturePressReleaseProc;
- long notifyStateProc;
+ long notifyProc;
Callback windowCallback2, windowCallback3, windowCallback4, windowCallback5, windowCallback6;
Callback snapshotDraw, changeValue;
Callback keyPressReleaseCallback, focusCallback, enterMotionScrollCallback, leaveCallback;
Callback gesturePressReleaseCallback;
- Callback notifyStateCallback;
+ Callback notifyCallback;
EventTable eventTable, filterTable;
static String APP_NAME = "SWT"; //$NON-NLS-1$
static String APP_VERSION = ""; //$NON-NLS-1$
@@ -155,6 +155,7 @@ public class Display extends Device {
long lastHandle;
Widget lastWidget;
Widget [] widgetTable;
+ Shell firstShell;
final static int GROW_SIZE = 1024;
static final int SWT_OBJECT_INDEX;
static final int SWT_OBJECT_INDEX1;
@@ -3452,14 +3453,15 @@ void initializeCallbacks () {
if (leaveProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
closuresProc [Widget.LEAVE] = leaveProc;
+ }
- notifyStateCallback = new Callback(this, "notifyStateProc", long.class, new Type[] {
- long.class, long.class, long.class}); //$NON-NLS-1$
- notifyStateProc = notifyStateCallback.getAddress();
- if (notifyStateProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
+ notifyCallback = new Callback(this, "notifyProc", long.class, new Type[] {
+ long.class, long.class, long.class}); //$NON-NLS-1$
+ notifyProc = notifyCallback.getAddress();
+ if (notifyProc == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
- closuresProc [Widget.NOTIFY_STATE] = notifyStateProc;
- }
+ closuresProc [Widget.NOTIFY_STATE] = notifyProc;
+ closuresProc [Widget.DPI_CHANGED] = notifyProc;
closuresProc [Widget.ACTIVATE] = windowProc2;
closuresProc [Widget.ACTIVATE_INVERSE] = windowProc2;
@@ -4534,15 +4536,15 @@ void releaseDisplay () {
gesturePressReleaseCallback = null;
gesturePressReleaseProc = 0;
- notifyStateCallback.dispose();
- notifyStateCallback = null;
- notifyStateProc = 0;
-
snapshotDraw.dispose();
snapshotDraw = null;
snapshotDrawProc = 0;
}
+ notifyCallback.dispose();
+ notifyCallback = null;
+ notifyProc = 0;
+
/* Dispose checkIfEvent callback */
checkIfEventCallback.dispose(); checkIfEventCallback = null;
checkIfEventProc = 0;
@@ -4866,6 +4868,15 @@ String debugInfoForIndex(long index) {
return s;
}
+void dpiChanged() {
+ this.scaleFactor = getDeviceZoom ();
+ DPIUtil.setDeviceZoom (scaleFactor);
+ Shell[] shells = getShells();
+ for (int i = 0; i < shells.length; i++) {
+ shells[i].layout(true, true);
+ }
+}
+
String dumpWidgetTableInfo() {
StringBuilder sb = new StringBuilder(", table size: ");
sb.append(widgetTable.length);
@@ -5867,10 +5878,21 @@ long leaveProc (long controller, long user_data) {
return widget.leaveProc(handle, user_data);
}
-long notifyStateProc (long gdk_handle, long param_spec, long user_data) {
- Widget widget = getWidget (user_data);
- if (widget == null) return 0;
- return widget.notifyStateProc(gdk_handle, user_data);
+long notifyProc (long object, long param_spec, long user_data) {
+ Widget widget = getWidget (object);
+ if (widget == null) {
+ widget = getWidget (user_data);
+ if (widget == null) {
+ return 0;
+ } else {
+ /*
+ * There is a corner case where the connected handle is actually
+ * a GdkSurface.
+ */
+ return widget.notifyProc(object, param_spec, Widget.NOTIFY_STATE);
+ }
+ }
+ return widget.notifyProc(object, param_spec, user_data);
}
boolean changeValue (long handle, int scroll, double value, long user_data) {
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
index f048086143..6688de4215 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
@@ -917,16 +917,20 @@ boolean hasBorder () {
@Override
void hookEvents () {
super.hookEvents ();
+ long notifyAddress = display.notifyCallback.getAddress();
+ if (display.firstShell == null) {
+ display.firstShell = this;
+ OS.g_signal_connect (shellHandle, OS.dpi_changed, notifyAddress, Widget.DPI_CHANGED);
+ }
if (GTK.GTK4) {
// Replace configure-event, map-event with generic event handler
if (eventHandle() == 0) {
OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [EVENT], 0, display.getClosure (EVENT), false);
}
// Replaced "window-state-event" with GdkSurface "notify::state", pass shellHandle as user_data
- long notifyStateAddress = display.notifyStateCallback.getAddress();
GTK.gtk_widget_realize(shellHandle);
long gdkSurface = gtk_widget_get_surface (shellHandle);
- OS.g_signal_connect (gdkSurface, OS.notify_state, notifyStateAddress, shellHandle);
+ OS.g_signal_connect (gdkSurface, OS.notify_state, notifyAddress, shellHandle);
OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [SIZE_ALLOCATE_GTK4], 0, display.getClosure (SIZE_ALLOCATE_GTK4), false);
} else {
OS.g_signal_connect_closure_by_id (shellHandle, display.signalIds [WINDOW_STATE_EVENT], 0, display.getClosure (WINDOW_STATE_EVENT), false);
@@ -1896,10 +1900,10 @@ long gtk_window_state_event (long widget, long event) {
}
@Override
-long notifyStateProc (long gdk_handle, long handle) {
+long notifyState (long object, long arg0) {
// GTK4 equivalent of gtk_window_state_event
assert GTK.GTK4;
- int gdkSurfaceState = GDK.gdk_surface_get_state (gdk_handle);
+ int gdkSurfaceState = GDK.gdk_surface_get_state (object);
minimized = (gdkSurfaceState & GDK.GDK_SURFACE_STATE_ICONIFIED) != 0;
maximized = (gdkSurfaceState & GDK.GDK_SURFACE_STATE_MAXIMIZED) != 0;
fullScreen = (gdkSurfaceState & GDK.GDK_SURFACE_STATE_FULLSCREEN) != 0;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
index fcaac7111a..51f0a779bc 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
@@ -236,7 +236,8 @@ public abstract class Widget {
static final int GESTURE_RELEASED = 101;
static final int NOTIFY_STATE = 102;
static final int SIZE_ALLOCATE_GTK4 = 103;
- static final int LAST_SIGNAL = 104;
+ static final int DPI_CHANGED = 104;
+ static final int LAST_SIGNAL = 105;
static final String IS_ACTIVE = "org.eclipse.swt.internal.control.isactive"; //$NON-NLS-1$
static final String KEY_CHECK_SUBWINDOW = "org.eclipse.swt.internal.control.checksubwindow"; //$NON-NLS-1$
@@ -528,6 +529,23 @@ public void dispose () {
release (true);
}
+long dpiChanged (long object, long arg0) {
+ int oldZoom = DPIUtil.getDeviceZoom() / 100;
+ int newZoom = GTK.gtk_widget_get_scale_factor(object);
+
+ if (oldZoom != newZoom) {
+ Event event = new Event();
+ event.type = SWT.ZoomChanged;
+ event.widget = this;
+ event.detail = newZoom;
+ event.doit = true;
+ notifyListeners(SWT.ZoomChanged, event);
+ display.dpiChanged();
+ }
+
+ return 0;
+}
+
void error (int code) {
SWT.error (code);
}
@@ -2177,7 +2195,15 @@ long leaveProc (long handle, long user_data) {
return result;
}
-long notifyStateProc (long gdk_handle, long handle) {
+long notifyProc (long object, long arg0, long user_data) {
+ switch ((int)user_data) {
+ case DPI_CHANGED: return dpiChanged(object, arg0);
+ case NOTIFY_STATE: return notifyState(object, arg0);
+ }
+ return 0;
+}
+
+long notifyState (long object, long argo0) {
return 0;
}

Back to the top