summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--NEWS3
-rw-r--r--src/x11_in_gtk3.c130
3 files changed, 96 insertions, 39 deletions
diff --git a/AUTHORS b/AUTHORS
index 8617acd..7e9e59e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -19,3 +19,5 @@ Contributors:
* Stefan Westerfeld
* Qt5 in Gtk2 support
* Initialization API
+ * Alexandros Theodotou
+ * X11 in Gtk3 improvements
diff --git a/NEWS b/NEWS
index e19ae3d..f608a94 100644
--- a/NEWS
+++ b/NEWS
@@ -2,8 +2,9 @@ suil (0.10.21) unstable; urgency=medium
* Add support for X11 in Qt6
* Fix library current_version on MacOS
+ * Monitor size hints for X11 in Gtk3
- -- David Robillard <d@drobilla.net> Thu, 11 Jul 2024 23:40:43 +0000
+ -- David Robillard <d@drobilla.net> Mon, 02 Dec 2024 03:05:37 +0000
suil (0.10.20) stable; urgency=medium
diff --git a/src/x11_in_gtk3.c b/src/x11_in_gtk3.c
index 0a1aaf9..138fdcb 100644
--- a/src/x11_in_gtk3.c
+++ b/src/x11_in_gtk3.c
@@ -39,10 +39,8 @@ typedef struct {
guint idle_id;
guint idle_ms;
guint idle_size_request_id;
- int initial_width;
- int initial_height;
- int req_width;
- int req_height;
+ XSizeHints size_hints;
+ gboolean size_hints_dirty;
} SuilX11Wrapper;
typedef struct {
@@ -197,6 +195,32 @@ idle_size_request(gpointer user_data)
}
static void
+update_wm_hints(SuilX11Wrapper* wrap, gboolean force)
+{
+ const XSizeHints old_hints = wrap->size_hints;
+ if (!wrap->size_hints_dirty && !force) {
+ return;
+ }
+
+ // Fetch hints from X
+ GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(wrap->plug));
+ long supplied = 0;
+ XGetWMNormalHints(GDK_WINDOW_XDISPLAY(window),
+ (Window)wrap->instance->ui_widget,
+ &wrap->size_hints,
+ &supplied);
+
+ // Preserve old "custom" size if necessary
+ if ((old_hints.flags & USSize) && old_hints.x && old_hints.y) {
+ wrap->size_hints.flags |= USSize;
+ wrap->size_hints.x = old_hints.x;
+ wrap->size_hints.y = old_hints.y;
+ }
+
+ wrap->size_hints_dirty = FALSE;
+}
+
+static void
forward_size_request(SuilX11Wrapper* socket, GtkAllocation* allocation)
{
GdkWindow* gwindow = gtk_widget_get_window(GTK_WIDGET(socket->plug));
@@ -266,16 +290,24 @@ suil_x11_wrapper_get_preferred_width(GtkWidget* widget,
Window ui_window = (Window)self->instance->ui_widget;
if (suil_x11_is_valid_child(xdisplay, GDK_WINDOW_XID(gwindow), ui_window)) {
- XSizeHints hints;
- memset(&hints, 0, sizeof(hints));
- long supplied = 0;
- XGetWMNormalHints(xdisplay, ui_window, &hints, &supplied);
- *natural_width =
- ((hints.flags & PBaseSize) ? hints.base_width : self->initial_width);
- *minimum_width =
- ((hints.flags & PMinSize) ? hints.min_width : self->req_width);
- } else {
- *natural_width = *minimum_width = self->req_width;
+ update_wm_hints(self, FALSE);
+
+ if (self->size_hints.flags & USSize) {
+ *natural_width = self->size_hints.width;
+ } else if (self->size_hints.flags & PBaseSize) {
+ *natural_width = self->size_hints.base_width;
+ } else if (self->size_hints.flags & PMinSize) {
+ *natural_width = self->size_hints.min_width;
+ } else {
+ g_warning("UI size hints have no base or minimum size");
+ XWindowAttributes attrs;
+ XGetWindowAttributes(xdisplay, ui_window, &attrs);
+ *natural_width = attrs.width;
+ }
+
+ *minimum_width = (self->size_hints.flags & PMinSize)
+ ? self->size_hints.min_width
+ : *natural_width;
}
}
@@ -290,16 +322,24 @@ suil_x11_wrapper_get_preferred_height(GtkWidget* widget,
Window ui_window = (Window)self->instance->ui_widget;
if (suil_x11_is_valid_child(xdisplay, GDK_WINDOW_XID(gwindow), ui_window)) {
- XSizeHints hints;
- memset(&hints, 0, sizeof(hints));
- long supplied = 0;
- XGetWMNormalHints(xdisplay, ui_window, &hints, &supplied);
- *natural_height =
- ((hints.flags & PBaseSize) ? hints.base_height : self->initial_height);
- *minimum_height =
- ((hints.flags & PMinSize) ? hints.min_height : self->req_height);
- } else {
- *natural_height = *minimum_height = self->req_height;
+ update_wm_hints(self, FALSE);
+
+ if (self->size_hints.flags & USSize) {
+ *natural_height = self->size_hints.height;
+ } else if (self->size_hints.flags & PBaseSize) {
+ *natural_height = self->size_hints.base_height;
+ } else if (self->size_hints.flags & PMinSize) {
+ *natural_height = self->size_hints.min_height;
+ } else {
+ g_warning("UI size hints have no base or minimum size");
+ XWindowAttributes attrs;
+ XGetWindowAttributes(xdisplay, ui_window, &attrs);
+ *natural_height = attrs.height;
+ }
+
+ *minimum_height = (self->size_hints.flags & PMinSize)
+ ? self->size_hints.min_height
+ : *natural_height;
}
}
@@ -332,13 +372,14 @@ suil_x11_wrapper_class_init(SuilX11WrapperClass* klass)
static void
suil_x11_wrapper_init(SuilX11Wrapper* self)
{
- self->plug = GTK_PLUG(gtk_plug_new(0));
- self->wrapper = NULL;
- self->instance = NULL;
- self->idle_iface = NULL;
- self->idle_ms = 1000 / 30; // 30 Hz default
- self->req_width = 0;
- self->req_height = 0;
+ self->plug = GTK_PLUG(gtk_plug_new(0));
+ self->wrapper = NULL;
+ self->instance = NULL;
+ self->idle_iface = NULL;
+ self->idle_ms = 1000 / 30; // 30 Hz default
+ self->size_hints_dirty = TRUE;
+
+ memset(&self->size_hints, 0, sizeof(self->size_hints));
}
static int
@@ -346,8 +387,14 @@ wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
{
SuilX11Wrapper* const wrap = SUIL_X11_WRAPPER(handle);
- wrap->req_width = width;
- wrap->req_height = height;
+ wrap->size_hints.width = width;
+ wrap->size_hints.height = height;
+ if (width > 0 && height > 0) {
+ wrap->size_hints.flags |= USSize;
+ }
+
+ // Fetch hints to get size constraints (probably) updated by plugin
+ wrap->size_hints_dirty = TRUE;
gtk_widget_queue_resize(GTK_WIDGET(handle));
return 0;
@@ -378,11 +425,18 @@ wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance)
Window ui_window = (Window)instance->ui_widget;
gdk_display_sync(display);
-
- XWindowAttributes attrs;
- XGetWindowAttributes(xdisplay, ui_window, &attrs);
- wrap->initial_width = attrs.width;
- wrap->initial_height = attrs.height;
+ if (suil_x11_is_valid_child(xdisplay, GDK_WINDOW_XID(gwindow), ui_window)) {
+ XWindowAttributes attrs;
+ XGetWindowAttributes(xdisplay, ui_window, &attrs);
+
+ update_wm_hints(wrap, TRUE);
+ if (!(wrap->size_hints.flags & PBaseSize)) {
+ // Fall back to using initial size as base size
+ wrap->size_hints.flags |= PBaseSize;
+ wrap->size_hints.base_width = attrs.width;
+ wrap->size_hints.base_height = attrs.height;
+ }
+ }
const LV2UI_Idle_Interface* idle_iface = NULL;
if (instance->descriptor->extension_data) {