Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package xwayland-satellite for 
openSUSE:Factory checked in at 2026-09-29 17:50:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/xwayland-satellite (Old)
 and      /work/SRC/openSUSE:Factory/.xwayland-satellite.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "xwayland-satellite"

Tue Sep 29 17:50:35 2026 rev:9 rq:1381270 version:0.8.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/xwayland-satellite/xwayland-satellite.changes    
2026-07-23 23:12:26.304694378 +0200
+++ 
/work/SRC/openSUSE:Factory/.xwayland-satellite.new.383539/xwayland-satellite.changes
        2026-09-29 17:51:54.561542631 +0200
@@ -1,0 +2,7 @@
+Mon Sep 28 23:34:32 UTC 2026 - Muhammad Akbar Yanuar Mantari <[email protected]>
+
+- Update to version 0.8.3:
+  * Fix new Steam popups
+  * Fix mouse cursor offset and blur on windows with decorations
+
+-------------------------------------------------------------------

Old:
----
  xwayland-satellite-0.8.2.tar.gz

New:
----
  xwayland-satellite-0.8.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ xwayland-satellite.spec ++++++
--- /var/tmp/diff_new_pack.ic9Rtm/_old  2026-09-29 17:51:55.446579588 +0200
+++ /var/tmp/diff_new_pack.ic9Rtm/_new  2026-09-29 17:51:55.448579672 +0200
@@ -18,7 +18,7 @@
 
 %bcond_with test
 Name:           xwayland-satellite
-Version:        0.8.2
+Version:        0.8.3
 Release:        0
 Summary:        Rootless Xwayland integration for Wayland compositors
 License:        MPL-2.0

++++++ vendor.tar.zst ++++++
/work/SRC/openSUSE:Factory/xwayland-satellite/vendor.tar.zst 
/work/SRC/openSUSE:Factory/.xwayland-satellite.new.383539/vendor.tar.zst 
differ: char 6, line 1

++++++ xwayland-satellite-0.8.2.tar.gz -> xwayland-satellite-0.8.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/xwayland-satellite-0.8.2/.github/ISSUE_TEMPLATE/bug_report.yaml 
new/xwayland-satellite-0.8.3/.github/ISSUE_TEMPLATE/bug_report.yaml
--- old/xwayland-satellite-0.8.2/.github/ISSUE_TEMPLATE/bug_report.yaml 
2026-07-22 02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/.github/ISSUE_TEMPLATE/bug_report.yaml 
2026-09-24 07:14:09.000000000 +0200
@@ -20,8 +20,16 @@
     id: problem
     attributes:
       label: Describe the issue.
-      value: |
-        **Please attach a log if applicable.**
+      description: |
+        Provide a debug log file.
+        If integrated with the compositor with `systemd` as the init system, 
logs can be retrieved by running 
+
+        `journalctl --grep=xwayland-sat --output=short-iso-precise -b > 
"$(date -Iseconds).log"`.
+
+        If integrated with a different init system, the logs will be collected 
by the configured `syslog` daemon.
+        See your distribution's/`syslog` daemon's documentation for where the 
logs are kept (likely somewhere in `/var/log`).
+
+        If run directly, the logs are output to the console.
     validations:
       required: true
   - type: textarea
@@ -30,7 +38,14 @@
       label: Steps to reproduce
   - type: checkboxes
     attributes:
-      label: Please confirm you have reproduced this on the latest commit.
+      label: Confirm you have reproduced this on the latest commit and 
attached log files.
+      description: "
+        To test the latest commit, build it according to the directions in the 
README, then launch it manually with
+        ```
+        ./xwayland-satellite -- :12
+        DISPLAY=:12 your-application
+        ```
+        "
       options:
         - label: I have reproduced this on the latest commit
           required: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/Cargo.lock 
new/xwayland-satellite-0.8.3/Cargo.lock
--- old/xwayland-satellite-0.8.2/Cargo.lock     2026-07-22 02:24:52.000000000 
+0200
+++ new/xwayland-satellite-0.8.3/Cargo.lock     2026-09-24 07:14:09.000000000 
+0200
@@ -400,6 +400,17 @@
 checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
 
 [[package]]
+name = "hostname"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "windows-link",
+]
+
+[[package]]
 name = "humantime"
 version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -832,6 +843,18 @@
 ]
 
 [[package]]
+name = "syslog"
+version = "7.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "019f1500a13379b7d051455df397c75770de6311a7a188a699499502704d9f10"
+dependencies = [
+ "hostname",
+ "libc",
+ "log",
+ "time",
+]
+
+[[package]]
 name = "termcolor"
 version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
@@ -1241,7 +1264,7 @@
 
 [[package]]
 name = "xwayland-satellite"
-version = "0.8.2"
+version = "0.8.3"
 dependencies = [
  "ab_glyph",
  "anyhow",
@@ -1256,6 +1279,7 @@
  "rustix",
  "sd-notify",
  "smithay-client-toolkit",
+ "syslog",
  "testwl",
  "tiny-skia",
  "vergen-gitcl",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/Cargo.toml 
new/xwayland-satellite-0.8.3/Cargo.toml
--- old/xwayland-satellite-0.8.2/Cargo.toml     2026-07-22 02:24:52.000000000 
+0200
+++ new/xwayland-satellite-0.8.3/Cargo.toml     2026-09-24 07:14:09.000000000 
+0200
@@ -17,7 +17,7 @@
 
 [package]
 name = "xwayland-satellite"
-version = "0.8.2"
+version = "0.8.3"
 authors = ["Shawn Wallace"]
 license = "MPL-2.0"
 description = "xwayland-satellite grants rootless Xwayland integration to any 
Wayland compositor implementing xdg_wm_base and viewporter. This is 
particularly useful for compositors that (understandably) do not want to go 
through implementing support for rootless Xwayland themselves."
@@ -40,6 +40,7 @@
 wl_drm = { path = "wl_drm" }
 log = "0.4.21"
 pretty_env_logger = "0.5.0"
+syslog = "7.0.0"
 xcb-util-cursor = "0.4"
 smithay-client-toolkit = { version = "0.20.0", default-features = false }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/README.md 
new/xwayland-satellite-0.8.3/README.md
--- old/xwayland-satellite-0.8.2/README.md      2026-07-22 02:24:52.000000000 
+0200
+++ new/xwayland-satellite-0.8.3/README.md      2026-09-24 07:14:09.000000000 
+0200
@@ -4,38 +4,41 @@
 
 Found a bug? [Open a bug 
report.](https://github.com/Supreeeme/xwayland-satellite/issues/new?template=bug_report.yaml)
 
-Need help troubleshooting, or have some other general question? [Ask on GitHub 
Discussions.](https://github.com/Supreeeme/xwayland-satellite/discussions)
+## Building
 
-## Dependencies
+xwayland-satellite has the following dependencies:
 - Xwayland >=23.1
 - xcb
 - xcb-util-cursor
+- cargo (building only)
 - clang (building only)
+- git (building only, optional)
 
-## Usage
-Run `xwayland-satellite`. You can specify an X display to use (i.e. `:12`). Be 
sure to set the same `DISPLAY` environment variable for any X11 clients.
-Because xwayland-satellite is a Wayland client (in addition to being a Wayland 
compositor), it will need to launch after your compositor launches, but 
obviously before any X11 applications.
-
-## Java applications
-Some (most?) Java applications may present themselves as a blank screen by 
default with satellite. To fix this, simply set the environment variable
-`_JAVA_AWT_WM_NONREPARENTING=1` before launching it to fix this. Unfortunately 
there is not a way for satellite to automatically do this.
-
-## Building
 ```
 # dev build
 cargo build
 # release build
 cargo build --release
-
-# run - will also build if not already built
-cargo run # --release
 ```
 
-## Systemd support
-xwayland-satellite can be built with systemd support - simply add `-F systemd` 
to your build command - i.e. `cargo build --release -F systemd`.
+In addition, xwayland-satellite also has the following optional features, 
which can be enabled by adding the `-F <feature>` flag to the `cargo build` 
command:
+
+### `systemd`
+With the `systemd` feature enabled, xwayland-satellite will send a state 
change notification when Xwayland has been initialized, allowing for services 
to depend on satellite's startup. This feature can be enabled without systemd 
installed, though it does nothing.
+
+### `fontconfig`
+The `fontconfig` feature uses fontconfig to load Open Sans at runtime instead 
of compiling Open Sans directly into the binary. The Open Sans font and 
`fontconfig` are runtime depenedencies when this feature is enabled.
+
+## Running
 
-With systemd support, satellite will send a state change notification when 
Xwayland has been initialized, allowing for having services dependent on 
satellite's startup.
+Because xwayland-satellite is a Wayland client (in addition to being a Wayland 
compositor), it will need to launch after your compositor launches, but 
obviously before any X11 applications.
+
+The `RUST_LOG` environment variable can be set to `debug` to output higher 
levels of logging.
+
+### Manually
+Run the `xwayland-satellite` binary, or use `cargo run` (with or without 
`--release`). You can specify an X display to use (i.e. `:12`). Be sure to set 
the same `DISPLAY` environment variable for any X11 clients. Setting the 
display allows you to choose which instance of `satellite` the X11 client 
communicates with, which can be useful for debugging crashes or bypassing 
automatically started instances (see below).
 
+### Systemd support
 An example service file is located in `resources/xwayland-satellite.service` - 
be sure to replace the `ExecStart` line with the proper location before using 
it.
 It can be placed in a systemd user unit directory (i.e. 
`$XDG_CONFIG_HOME/systemd/user` or `/etc/systemd/user`),
 and be launched and enabled with `systemctl --user enable --now 
xwayland-satellite`.
@@ -44,17 +47,17 @@
 
 Note that you *do not* need the systemd service if the compositor already 
integrates xwayland-satellite (see below).
 
-## Scaling/HiDPI
-For most GTK and Qt apps, xwayland-satellite should automatically scale them 
properly. Note that for mixed DPI monitor setups, satellite will choose
-the smallest monitor's DPI, meaning apps may have small text on other monitors.
+### Compositor integration
+Satellite supports passing through the `-listenfd` Xwayland argument. What 
this means is you can integrate satellite
+(and by extension Xwayland) into your compositor, and do things like on demand 
activation. Note that you *must* pass
+a display number to satellite as the first argument, and then the `-listenfd` 
argument.
 
-Other miscellaneous apps (such as Wine apps) may have small text on HiDPI 
displays. It is application dependent on getting apps to scale properly with 
satellite,
-so you will have to figure out what app specific config needs to be set. See 
[the Arch Wiki on HiDPI](https://wiki.archlinux.org/title/HiDPI) for a good 
place start.
+You can view [Niri's implementation of this 
integration](https://github.com/YaLTeR/niri/pull/1728/files) for understanding
+how it should work.
 
-Satellite acts as an Xsettings manager for setting scaling related settings, 
but will get out of the way of other Xsettings managers.
-To manually set these settings, try 
[xsettingsd](https://codeberg.org/derat/xsettingsd) or another Xsettings 
manager.
+If `satellite` is integrated into your compositor, updating either 
`xwayland-satellite` or your compositor's satellite settings requires 
restarting the compositor. To test latest commit and/or patches without 
restarting the compositor, add a display when launching `xwayland-satellite` 
and use the same `DISPLAY` environment variables for applications you wish to 
test.
 
-## Wayland protocols used
+## Wayland protocols
 The host compositor **must** implement the following protocols/interfaces for 
satellite to function:
 - Core interfaces (wl_output, wl_surface, wl_compositor, etc)
 - xdg_shell (xdg_wm_base, xdg_surface, xdg_popup, xdg_toplevel)
@@ -63,15 +66,27 @@
 Additionally, satellite can *optionally* take advantage of the following 
protocols:
 - Linux dmabuf
 - XDG activation
+- XDG decoration
 - XDG foreign
 - Pointer constraints
+- Primary selection
 - Tablet input
 - Fractional scale
 
-## Compositor integration
-Satellite supports passing through the `-listenfd` Xwayland argument. What 
this means is you can integrate satellite
-(and by extension Xwayland) into your compositor, and do things like on demand 
activation. Note that you *must* pass
-a display number to satellite as the first argument, and then the `-listenfd` 
argument.
+## Troubleshooting
 
-You can view [Niri's implementation of this 
integration](https://github.com/YaLTeR/niri/pull/1728/files) for understanding
-how it should work.
+Need help troubleshooting, or have some other general question? [Ask on GitHub 
Discussions.](https://github.com/Supreeeme/xwayland-satellite/discussions)
+
+### Java applications
+Some Java applications may present themselves as a blank screen by default 
with satellite. To fix this, simply set the environment variable
+`_JAVA_AWT_WM_NONREPARENTING=1` before launching it to fix this. Although 
`satellite` cannot automatically do this, you can configure Java to do this by 
adding `set _JAVA_AWT_WM_NONREPARENTING=1` to `/etc/profile.d/jre.sh`.
+
+### Scaling/HiDPI
+For most GTK and Qt apps, xwayland-satellite should automatically scale them 
properly. Note that for mixed DPI monitor setups, satellite will choose
+the smallest monitor's DPI, meaning apps may have small text on other monitors.
+
+Other miscellaneous apps (such as Wine apps) may have small text on HiDPI 
displays. It is application dependent on getting apps to scale properly with 
satellite,
+so you will have to figure out what app specific config needs to be set. See 
[the Arch Wiki on HiDPI](https://wiki.archlinux.org/title/HiDPI) for a good 
place start.
+
+Satellite acts as an Xsettings manager for setting scaling related settings, 
but will get out of the way of other Xsettings managers.
+To manually set these settings, try 
[xsettingsd](https://codeberg.org/derat/xsettingsd) or another Xsettings 
manager.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/lib.rs 
new/xwayland-satellite-0.8.3/src/lib.rs
--- old/xwayland-satellite-0.8.2/src/lib.rs     2026-07-22 02:24:52.000000000 
+0200
+++ new/xwayland-satellite-0.8.3/src/lib.rs     2026-09-24 07:14:09.000000000 
+0200
@@ -20,6 +20,7 @@
     fn set_window_dims(&mut self, window: x::Window, dims: 
PendingSurfaceState) -> bool;
     fn set_fullscreen(&mut self, window: x::Window, fullscreen: bool);
     fn focus_window(&mut self, window: x::Window, output_name: Option<String>);
+    fn send_take_focus(&mut self, window: x::Window);
     fn close_window(&mut self, window: x::Window);
     fn unmap_window(&mut self, window: x::Window);
     fn raise_to_top(&mut self, window: x::Window);
@@ -110,6 +111,8 @@
 
     // Now that Xwayland spawned and got the listenfds, we can close them here.
     drop(fds);
+    // Close our copy of the WM socket so Xwayland exiting produces EOF on 
xsock_wl.
+    drop(xsock_xwl);
 
     let xwl_pid = xwayland.id();
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/main.rs 
new/xwayland-satellite-0.8.3/src/main.rs
--- old/xwayland-satellite-0.8.2/src/main.rs    2026-07-22 02:24:52.000000000 
+0200
+++ new/xwayland-satellite-0.8.3/src/main.rs    2026-09-24 07:14:09.000000000 
+0200
@@ -1,11 +1,9 @@
 use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
 
 fn main() {
-    pretty_env_logger::formatted_timed_builder()
-        .filter_level(log::LevelFilter::Info)
-        .parse_default_env()
-        .init();
-    xwayland_satellite::main(parse_args());
+    let arg_data = parse_args();
+    init_logger(!arg_data.listenfds.is_empty());
+    xwayland_satellite::main(arg_data);
 }
 
 #[derive(Default)]
@@ -246,3 +244,33 @@
 
     data
 }
+
+fn init_logger(integrated: bool) {
+    if integrated {
+        match syslog::unix(syslog::Formatter3164::default()) {
+            Ok(syslog) => {
+                
log::set_boxed_logger(Box::new(syslog::BasicLogger::new(syslog))).unwrap();
+                log::set_max_level(log::LevelFilter::Debug);
+                std::panic::set_hook(Box::new(|info| {
+                    let thread = std::thread::current();
+                    let name = thread.name().unwrap_or("<unnamed");
+                    let location = info.location().unwrap();
+                    log::error!("thread '{name}' panicked at {location}:");
+                    if let Some(s) = info.payload().downcast_ref::<&str>() {
+                        log::error!("{s}");
+                    } else if let Some(s) = 
info.payload().downcast_ref::<String>() {
+                        log::error!("{s}");
+                    }
+                }));
+                return;
+            }
+            Err(e) => {
+                eprintln!("failed to start syslog: {e:?}");
+            }
+        };
+    }
+    pretty_env_logger::formatted_timed_builder()
+        .filter_level(log::LevelFilter::Info)
+        .parse_default_env()
+        .init();
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/server/dispatch.rs 
new/xwayland-satellite-0.8.3/src/server/dispatch.rs
--- old/xwayland-satellite-0.8.2/src/server/dispatch.rs 2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/src/server/dispatch.rs 2026-09-24 
07:14:09.000000000 +0200
@@ -234,7 +234,7 @@
                         client,
                         server,
                         viewport,
-                        scale: SurfaceScaleFactor(1.0),
+                        scale: SurfaceScaleFactor(state.current_scale),
                     },
                 );
                 if let Some(f) = fractional {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/server/event.rs 
new/xwayland-satellite-0.8.3/src/server/event.rs
--- old/xwayland-satellite-0.8.2/src/server/event.rs    2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/src/server/event.rs    2026-09-24 
07:14:09.000000000 +0200
@@ -295,7 +295,7 @@
                 &SurfaceScaleFactor,
                 &x::Window,
                 &mut WindowData,
-                &mut SurfaceRole,
+                &SurfaceRole,
             )>();
             let (scale_factor, window, window_data, role) = 
query.get().unwrap();
 
@@ -307,8 +307,19 @@
             } else {
                 window_data.attrs.dims.width
             };
-            let mut height = if pending.height > 0 {
-                (pending.height as f64 * scale_factor.0) as u16
+            let height = if pending.height > 0 {
+                let mut logical_height = pending.height;
+                if let SurfaceRole::Toplevel(Some(toplevel)) = role {
+                    if let Some(d) = &toplevel.decoration.satellite {
+                        let surface_width = (width as f64 / 
scale_factor.0).ceil() as i32;
+                        if d.will_draw_decorations(surface_width) {
+                            logical_height = (logical_height
+                                - DecorationsDataSatellite::TITLEBAR_HEIGHT)
+                                
.max(DecorationsDataSatellite::TITLEBAR_HEIGHT);
+                        }
+                    }
+                }
+                (logical_height as f64 * scale_factor.0) as u16
             } else {
                 window_data.attrs.dims.height
             };
@@ -317,20 +328,6 @@
                 data.get::<&WlSurface>().unwrap().id(),
             );
 
-            if let SurfaceRole::Toplevel(Some(toplevel)) = &*role {
-                if let Some(d) = &toplevel.decoration.satellite {
-                    let surface_width = (width as f64 / scale_factor.0) as i32;
-                    if d.will_draw_decorations(surface_width) {
-                        height = height
-                            .saturating_sub(
-                                (DecorationsDataSatellite::TITLEBAR_HEIGHT as 
f64 * scale_factor.0)
-                                    as u16,
-                            )
-                            .max(DecorationsDataSatellite::TITLEBAR_HEIGHT as 
u16);
-                    }
-                }
-            }
-
             window_data.attrs.dims = WindowDims {
                 x: x as i16,
                 y: y as i16,
@@ -457,6 +454,7 @@
                             window,
                             output_name: None,
                             is_popup: true,
+                            has_take_focus: window_data.attrs.has_take_focus,
                         });
                     }
                 }
@@ -505,32 +503,33 @@
     debug!("{} viewport: {width}x{height}", surface.id());
 
     if let Some(hints) = size_hints {
-        let Some(data) = toplevel_data else {
-            return;
-        };
-
-        let decorations_height = if data.decoration.satellite.is_some() {
-            DecorationsDataSatellite::TITLEBAR_HEIGHT
-        } else {
-            0
+        if let Some(data) = toplevel_data {
+            update_size_hints(data, hints, scale_factor.0);
         };
+    }
+}
 
-        if let Some(min) = hints.min_size {
-            debug!(
-                "updated min height: {}",
-                (min.height as f64 / scale_factor.0) as i32 + 
decorations_height
-            );
-            data.toplevel.set_min_size(
-                (min.width as f64 / scale_factor.0) as i32,
-                (min.height as f64 / scale_factor.0) as i32 + 
decorations_height,
-            );
-        }
-        if let Some(max) = hints.max_size {
-            data.toplevel.set_max_size(
-                (max.width as f64 / scale_factor.0) as i32,
-                (max.height as f64 / scale_factor.0) as i32 + 
decorations_height,
-            );
-        }
+pub(super) fn update_size_hints(data: &ToplevelData, hints: &WmNormalHints, 
scale: f64) {
+    let decorations_height = if data.decoration.satellite.is_some() {
+        DecorationsDataSatellite::TITLEBAR_HEIGHT
+    } else {
+        0
+    };
+    if let Some(min_size) = &hints.min_size {
+        data.toplevel.set_min_size(
+            (min_size.width as f64 / scale) as i32,
+            ((min_size.height as f64 / scale) as 
i32).saturating_add(decorations_height),
+        );
+    } else {
+        data.toplevel.set_min_size(0, 0);
+    }
+    if let Some(max_size) = &hints.max_size {
+        data.toplevel.set_max_size(
+            (max_size.width as f64 / scale) as i32,
+            ((max_size.height as f64 / scale) as 
i32).saturating_add(decorations_height),
+        );
+    } else {
+        data.toplevel.set_max_size(0, 0);
     }
 }
 
@@ -869,10 +868,13 @@
                     serial,
                 ));
                 let output_name = get_output_name(output, &state.world);
+                let window_data = data.get::<&WindowData>();
+                let has_take_focus = window_data.as_ref().is_some_and(|d| 
d.attrs.has_take_focus);
                 state.to_focus = Some(FocusData {
                     window: *window,
                     output_name,
                     is_popup: false,
+                    has_take_focus,
                 });
                 keyboard.enter(serial, surface, keys);
             }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/server/mod.rs 
new/xwayland-satellite-0.8.3/src/server/mod.rs
--- old/xwayland-satellite-0.8.2/src/server/mod.rs      2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/src/server/mod.rs      2026-09-24 
07:14:09.000000000 +0200
@@ -101,9 +101,10 @@
 
 #[derive(Default, Debug)]
 struct WindowAttributes {
-    acquire_input_via_wm: bool,
+    accepts_input: bool,
     has_take_focus: bool,
     role: WindowRole,
+    override_redirect: bool,
     dims: WindowDims,
     size_hints: Option<WmNormalHints>,
     title: Option<WmName>,
@@ -114,9 +115,8 @@
 }
 
 impl WindowAttributes {
-    /// AKA "Passive" input model
     fn require_wm_focus(&self) -> bool {
-        self.acquire_input_via_wm && !self.has_take_focus
+        !self.override_redirect && (self.has_take_focus || self.accepts_input)
     }
 }
 
@@ -140,6 +140,7 @@
             mapped: false,
             attrs: WindowAttributes {
                 role: WindowRole::new_basic(override_redirect),
+                override_redirect,
                 dims,
                 ..Default::default()
             },
@@ -398,6 +399,7 @@
     window: x::Window,
     output_name: Option<String>,
     is_popup: bool,
+    has_take_focus: bool,
 }
 
 #[derive(Copy, Clone, Default)]
@@ -422,6 +424,9 @@
     fn focus_window(&mut self, _: x::Window, _: Option<String>) {
         debug!("could not focus window without XWayland initialized");
     }
+    fn send_take_focus(&mut self, _: x::Window) {
+        debug!("could not send take focus without XWayland initialized");
+    }
     fn close_window(&mut self, _: x::Window) {
         debug!("could not close window without XWayland initialized");
     }
@@ -485,6 +490,7 @@
     global_offset_updated: bool,
     updated_outputs: Vec<Entity>,
     new_scale: Option<f64>,
+    current_scale: f64,
 }
 
 impl<S: X11Selection> ServerState<NoConnection<S>> {
@@ -593,6 +599,7 @@
             global_offset_updated: false,
             updated_outputs: Vec::new(),
             new_scale: None,
+            current_scale: 1.0,
             decoration_manager,
             world,
         };
@@ -731,6 +738,7 @@
 
                 debug!("Using new scale {scale}");
                 self.new_scale = Some(scale);
+                self.current_scale = scale;
             }
         }
 
@@ -739,15 +747,20 @@
                 window,
                 output_name,
                 is_popup,
+                has_take_focus,
             }) = self.to_focus.take()
             {
                 debug!(
-                    "focusing {} {window:?}",
+                    "focusing (take_focus={has_take_focus:?}) {} {window:?}",
                     if is_popup { "popup" } else { "window" }
                 );
-                self.connection.focus_window(window, output_name);
-                if !is_popup {
-                    self.last_focused_toplevel = Some(window);
+                if has_take_focus {
+                    self.connection.send_take_focus(window);
+                } else {
+                    self.connection.focus_window(window, output_name);
+                    if !is_popup {
+                        self.last_focused_toplevel = Some(window);
+                    }
                 }
             } else if self.unfocus {
                 self.connection.focus_window(x::WINDOW_NONE, None);
@@ -885,9 +898,24 @@
         self.windows.insert(window, id);
     }
 
+    pub fn set_override_redirect(&mut self, window: x::Window, 
override_redirect: bool) {
+        let Some(id) = self.windows.get(&window).copied() else {
+            debug!(
+                "not setting override_redirect {override_redirect} for unknown 
window {window:?}"
+            );
+            return;
+        };
+
+        self.world
+            .get::<&mut WindowData>(id)
+            .unwrap()
+            .attrs
+            .override_redirect = override_redirect;
+    }
+
     pub fn set_window_role(&mut self, window: x::Window, role: WindowRole) {
         let Some(id) = self.windows.get(&window).copied() else {
-            debug!("not setting popup for unknown window {window:?}");
+            debug!("not setting role {role:?} for unknown window {window:?}");
             return;
         };
 
@@ -966,7 +994,7 @@
 
         let attrs = &mut self.world.get::<&mut WindowData>(id).unwrap().attrs;
         attrs.group = hints.window_group;
-        attrs.acquire_input_via_wm = hints.acquire_input_via_wm;
+        attrs.accepts_input = hints.accepts_input;
     }
 
     pub fn set_take_focus(&mut self, window: x::Window, has_take_focus: bool) {
@@ -996,27 +1024,7 @@
             debug!("setting {window:?} hints {hints:?}");
             let mut query = data.query::<(&SurfaceRole, 
&SurfaceScaleFactor)>();
             if let Some((SurfaceRole::Toplevel(Some(data)), scale_factor)) = 
query.get() {
-                let decorations_height = if 
data.decoration.satellite.is_some() {
-                    DecorationsDataSatellite::TITLEBAR_HEIGHT
-                } else {
-                    0
-                };
-                if let Some(min_size) = &hints.min_size {
-                    data.toplevel.set_min_size(
-                        (min_size.width as f64 / scale_factor.0) as i32,
-                        (min_size.height as f64 / scale_factor.0) as i32 + 
decorations_height,
-                    );
-                } else {
-                    data.toplevel.set_min_size(0, 0);
-                }
-                if let Some(max_size) = &hints.max_size {
-                    data.toplevel.set_max_size(
-                        (max_size.width as f64 / scale_factor.0) as i32,
-                        (max_size.height as f64 / scale_factor.0) as i32 + 
decorations_height,
-                    );
-                } else {
-                    data.toplevel.set_max_size(0, 0);
-                }
+                event::update_size_hints(data, &hints, scale_factor.0);
             }
             win.attrs.size_hints = Some(hints);
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/server/tests.rs 
new/xwayland-satellite-0.8.3/src/server/tests.rs
--- old/xwayland-satellite-0.8.2/src/server/tests.rs    2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/src/server/tests.rs    2026-09-24 
07:14:09.000000000 +0200
@@ -160,6 +160,7 @@
 #[derive(Default)]
 struct FakeXConnection {
     focused_window: Option<Window>,
+    send_take_focus_window: Option<Window>,
     windows: HashMap<Window, WindowData>,
     set_window_dims_counter: usize,
 }
@@ -234,6 +235,15 @@
         self.focused_window = window.into();
     }
 
+    #[track_caller]
+    fn send_take_focus(&mut self, window: x::Window) {
+        assert!(
+            self.windows.contains_key(&window),
+            "Unknown window: {window:?}"
+        );
+        self.send_take_focus_window = window.into();
+    }
+
     fn raise_to_top(&mut self, window: Window) {
         assert!(
             self.windows.contains_key(&window),
@@ -741,6 +751,10 @@
             assert!(surface_data.buffer.is_some());
         }
 
+        let scale = self.satellite.current_scale;
+        let expected_width = (100.0 * scale) as u16;
+        let expected_height = (100.0 * scale) as u16;
+
         let win_data = self.connection().windows.get(&window).map(|d| &d.dims);
         assert!(
             matches!(
@@ -748,9 +762,9 @@
                 Some(&super::WindowDims {
                     x: 0,
                     y: 0,
-                    width: 100,
-                    height: 100
-                })
+                    width,
+                    height
+                }) if width == expected_width && height == expected_height
             ),
             "Incorrect window geometry: {win_data:?}"
         );
@@ -855,6 +869,55 @@
     }
 
     #[track_caller]
+    fn setup_popup_focus_case(
+        &mut self,
+        comp: &Compositor,
+        override_redirect: bool,
+        accepts_input: bool,
+        take_focus: bool,
+    ) -> (Window, Window) {
+        let win_toplevel = Window::new(1);
+        self.create_toplevel(comp, win_toplevel);
+
+        let win_popup = Window::new(2);
+        let (buffer, surface) = comp.create_surface();
+        let data = WindowData {
+            mapped: true,
+            dims: WindowDims {
+                x: 10,
+                y: 20,
+                width: 100,
+                height: 50,
+            },
+            fullscreen: false,
+        };
+        self.new_window(win_popup, override_redirect, data);
+        if !override_redirect {
+            self.satellite
+                .set_window_role(win_popup, crate::xstate::WindowRole::Popup);
+        }
+
+        self.satellite.set_win_hints(
+            win_popup,
+            super::WmHints {
+                window_group: None,
+                accepts_input,
+            },
+        );
+        if take_focus {
+            self.satellite.set_take_focus(win_popup, true);
+        }
+        self.map_window(comp, win_popup, &surface.obj, &buffer);
+        self.run();
+
+        let popup_id = self.check_new_surface();
+        self.testwl.configure_popup(popup_id);
+        self.run();
+
+        (win_toplevel, win_popup)
+    }
+
+    #[track_caller]
     fn assert_window_dimensions(
         &self,
         window: x::Window,
@@ -1338,7 +1401,7 @@
         win,
         super::WmHints {
             window_group: Some(prop_win),
-            acquire_input_via_wm: false,
+            accepts_input: false,
         },
     );
     f.satellite.map_window(win);
@@ -1643,103 +1706,51 @@
 }
 
 #[test]
-fn popup_no_focus_without_input_hint() {
-    let (mut f, comp) = TestFixture::new_with_compositor();
-
-    let win_toplevel = Window::new(1);
-    let (_, toplevel_id) = f.create_toplevel(&comp, win_toplevel);
+fn popup_override_redirect_never_focused_nor_offered() {
+    for accepts_input in [true, false] {
+        for take_focus in [false, true] {
+            let (mut f, comp) = TestFixture::new_with_compositor();
+
+            let (win_toplevel, _) =
+                f.setup_popup_focus_case(&comp, true, accepts_input, 
take_focus);
+            assert_eq!(
+                f.connection().focused_window,
+                Some(win_toplevel),
+                "accepts_input={accepts_input:?} take_focus={take_focus}"
+            );
+            assert_eq!(
+                f.connection().send_take_focus_window,
+                None,
+                "accepts_input={accepts_input:?} take_focus={take_focus}"
+            );
+        }
+    }
+}
 
-    // A popup without acquire_input_via_wm should not receive focus.
-    let win_popup = Window::new(2);
-    f.create_popup(
-        &comp,
-        PopupBuilder::new(win_popup, win_toplevel, toplevel_id),
-    );
-    assert_eq!(f.connection().focused_window, Some(win_toplevel));
+#[test]
+fn popup_send_take_focus_when_advertised() {
+    for accepts_input in [true, false] {
+        let (mut f, comp) = TestFixture::new_with_compositor();
+
+        let (win_toplevel, win_popup) = f.setup_popup_focus_case(&comp, false, 
accepts_input, true);
+        assert_eq!(f.connection().focused_window, Some(win_toplevel));
+        assert_eq!(f.connection().send_take_focus_window, Some(win_popup));
+    }
 }
 
 #[test]
 fn popup_focus_on_map_with_input_hint() {
     let (mut f, comp) = TestFixture::new_with_compositor();
 
-    let win_toplevel = Window::new(1);
-    let (_, toplevel_id) = f.create_toplevel(&comp, win_toplevel);
-
-    // A popup with acquire_input_via_wm should receive X11 keyboard focus
-    // at map time, matching what a real X11 WM does for windows with
-    // WM_HINTS input=True.
-    let win_popup = Window::new(2);
-    let (buffer, surface) = comp.create_surface();
-    let dims = WindowDims {
-        x: 10,
-        y: 20,
-        width: 100,
-        height: 50,
-    };
-    let data = WindowData {
-        mapped: true,
-        dims,
-        fullscreen: false,
-    };
-    f.new_window(win_popup, true, data);
-    f.satellite.set_win_hints(
-        win_popup,
-        super::WmHints {
-            window_group: None,
-            acquire_input_via_wm: true,
-        },
-    );
-    f.map_window(&comp, win_popup, &surface.obj, &buffer);
-    f.run();
-
-    let popup_id = f.check_new_surface();
-    assert_ne!(popup_id, toplevel_id);
-
-    f.testwl.configure_popup(popup_id);
-    f.run();
-
-    // Focus should have been given directly to the popup at map time.
+    let (_, win_popup) = f.setup_popup_focus_case(&comp, false, true, false);
     assert_eq!(f.connection().focused_window, Some(win_popup));
 }
 
 #[test]
-fn popup_no_focus_input_hint_wm_take_focus() {
+fn popup_no_focus_without_input_hint() {
     let (mut f, comp) = TestFixture::new_with_compositor();
 
-    let win_toplevel = Window::new(1);
-    let (_, toplevel_id) = f.create_toplevel(&comp, win_toplevel);
-
-    let win_popup = Window::new(2);
-    let (buffer, surface) = comp.create_surface();
-    let dims = WindowDims {
-        x: 10,
-        y: 20,
-        width: 100,
-        height: 50,
-    };
-    let data = WindowData {
-        mapped: true,
-        dims,
-        fullscreen: false,
-    };
-    f.new_window(win_popup, true, data);
-    f.satellite.set_win_hints(
-        win_popup,
-        super::WmHints {
-            window_group: None,
-            acquire_input_via_wm: true,
-        },
-    );
-    f.satellite.set_take_focus(win_popup, true);
-    f.map_window(&comp, win_popup, &surface.obj, &buffer);
-    f.run();
-
-    let popup_id = f.check_new_surface();
-    assert_ne!(popup_id, toplevel_id);
-
-    f.testwl.configure_popup(popup_id);
-    f.run();
-
+    let (win_toplevel, _) = f.setup_popup_focus_case(&comp, false, false, 
false);
     assert_eq!(f.connection().focused_window, Some(win_toplevel));
 }
 
@@ -3069,6 +3080,25 @@
     assert_eq!(f.satellite.inner.new_scale, Some(2.0));
 }
 
+#[track_caller]
+fn check_window_and_viewport_size(
+    f: &TestFixture<FakeXConnection>,
+    window: Window,
+    id: testwl::SurfaceId,
+    width: u16,
+    height: u16,
+) {
+    let dims = f.connection().window(window).dims;
+    assert_eq!((dims.width, dims.height), (width, height), "X window size");
+    let data = f.testwl.get_surface_data(id).unwrap();
+    let viewport = data.viewport.as_ref().unwrap();
+    assert_eq!(
+        (viewport.width, viewport.height),
+        (width as i32, height as i32),
+        "viewport size"
+    );
+}
+
 #[test]
 fn client_side_decorations() {
     let (mut f, compositor) = TestFixture::new_with_compositor();
@@ -3079,16 +3109,8 @@
     f.testwl.configure_toplevel(id, 100, 100, vec![]);
     f.run();
 
-    let data = f.connection().window(window);
-    assert_eq!(
-        data.dims,
-        WindowDims {
-            x: 0,
-            y: 0,
-            width: 100,
-            height: 75
-        }
-    );
+    check_window_and_viewport_size(&f, window, id, 100, 75);
+
     let subsurface_id = f.testwl.last_created_surface_id().unwrap();
     assert_ne!(subsurface_id, id);
     let data = f.testwl.get_surface_data(subsurface_id).unwrap();
@@ -3103,16 +3125,8 @@
     f.testwl
         .configure_toplevel(id, 100, 100, 
vec![xdg_toplevel::State::Fullscreen]);
     f.run();
-    let data = f.connection().window(window);
-    assert_eq!(
-        data.dims,
-        WindowDims {
-            x: 0,
-            y: 0,
-            width: 100,
-            height: 100
-        }
-    );
+    check_window_and_viewport_size(&f, window, id, 100, 100);
+
     let data = f.testwl.get_surface_data(subsurface_id).unwrap();
     assert!(data.buffer.is_none());
 
@@ -3128,21 +3142,58 @@
     f.testwl.configure_toplevel(id, 100, 100, vec![]);
     f.run();
 
-    let data = f.connection().window(window);
-    assert_eq!(
-        data.dims,
-        WindowDims {
-            x: 0,
-            y: 0,
-            width: 100,
-            height: 100
-        }
-    );
+    check_window_and_viewport_size(&f, window, id, 100, 100);
     assert!(f.testwl.get_surface_data(subsurface_id).is_none());
     assert!(!subsurface.is_alive());
 }
 
 #[test]
+fn client_side_decorations_fractional_scale() {
+    use super::decoration::DecorationsDataSatellite;
+
+    let mut f = TestFixture::new_pre_connect(|testwl| {
+        testwl.enable_fractional_scale();
+    });
+    let compositor = f.compositor();
+    let (_, output) = f.new_output(0, 0);
+    let window = Window::new(1);
+    let (_, id) = f.create_toplevel(&compositor, window);
+    f.testwl.move_surface_to_output(id, &output);
+    f.testwl
+        .force_decoration_mode(id, 
zxdg_toplevel_decoration_v1::Mode::ClientSide);
+    f.run();
+
+    let content_height = 100.0 - 
f64::from(DecorationsDataSatellite::TITLEBAR_HEIGHT);
+    let scales: [(f64, u32); 2] = [(1.5, 180), (1.25, 150)];
+    for (scale, preferred) in scales {
+        let data = f.testwl.get_surface_data(id).unwrap();
+        data.fractional
+            .as_ref()
+            .expect("Missing fractional scale")
+            .preferred_scale(preferred);
+        f.testwl.configure_toplevel(id, 100, 100, vec![]);
+        f.run();
+        f.run();
+
+        let x_width = (100.0 * scale).floor() as u16;
+        let x_height = (content_height * scale) as u16;
+        let dims = f.connection().window(window).dims;
+        assert_eq!(
+            (dims.width, dims.height),
+            (x_width, x_height),
+            "X window size at scale {scale}"
+        );
+        let data = f.testwl.get_surface_data(id).unwrap();
+        let viewport = data.viewport.as_ref().unwrap();
+        assert_eq!(
+            (viewport.width, viewport.height),
+            (100, content_height as i32),
+            "viewport size at scale {scale}"
+        );
+    }
+}
+
+#[test]
 fn client_side_decorations_no_global() {
     let mut f = TestFixture::new_pre_connect(|testwl| {
         testwl.disable_decorations_global();
@@ -3201,16 +3252,8 @@
     f.testwl.configure_toplevel(id, 100, 100, vec![]);
     f.run();
 
-    let data = f.connection().window(window);
-    assert_eq!(
-        data.dims,
-        WindowDims {
-            x: 0,
-            y: 0,
-            width: 100,
-            height: 75
-        }
-    );
+    check_window_and_viewport_size(&f, window, id, 100, 75);
+
     let subsurface_id = f.testwl.last_created_surface_id().unwrap();
     assert_ne!(subsurface_id, id);
     let data = f.testwl.get_surface_data(subsurface_id).unwrap();
@@ -3224,6 +3267,12 @@
         data.role
     );
 
+    // Weston seems to do this when a window is deactivated. Since the stored 
window data's height
+    // is used as a fallback in this case, do not reapply the height reduction 
from the titlebar.
+    f.testwl.configure_toplevel(id, 0, 0, vec![]);
+    f.run();
+    check_window_and_viewport_size(&f, window, id, 100, 75);
+
     let dims = WindowDims {
         x: 0,
         y: 0,
@@ -3256,6 +3305,41 @@
         .set_win_title(window, WmName::WmName("window".into()));
 }
 
+#[test]
+fn decorations_max_height_int_max() {
+    let (mut f, compositor) = TestFixture::new_with_compositor();
+    let window = Window::new(1);
+    let (_, id) = f.create_toplevel(&compositor, window);
+    f.testwl
+        .force_decoration_mode(id, 
zxdg_toplevel_decoration_v1::Mode::ClientSide);
+    f.testwl.configure_toplevel(id, 1, 100, vec![]);
+    f.run();
+
+    // When calculating the Wayland max size from the X size hints, the 
titlebar height is added to
+    // the height hint, but obviously this should not overflow the size hint.
+    f.satellite.set_size_hints(
+        window,
+        super::WmNormalHints {
+            min_size: None,
+            max_size: Some(WinSize {
+                width: i32::MAX,
+                height: i32::MAX,
+            }),
+        },
+    );
+    f.run();
+
+    let data = f.testwl.get_surface_data(id).unwrap();
+    let toplevel = data.toplevel();
+    assert_eq!(
+        toplevel.max_size,
+        Some(testwl::Vec2 {
+            x: i32::MAX,
+            y: i32::MAX
+        })
+    );
+}
+
 /// See Pointer::handle_event for an explanation.
 #[test]
 fn popup_pointer_motion_workaround() {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/xstate/mod.rs 
new/xwayland-satellite-0.8.3/src/xstate/mod.rs
--- old/xwayland-satellite-0.8.2/src/xstate/mod.rs      2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/src/xstate/mod.rs      2026-09-24 
07:14:09.000000000 +0200
@@ -4,6 +4,7 @@
 use selection::{Selection, SelectionState};
 #[cfg(test)]
 mod tests;
+mod xresources;
 
 use crate::XConnection;
 use bitflags::bitflags;
@@ -653,6 +654,7 @@
 
         let transient_for = self.get_transient_for(window)?;
         let override_redirect = self.get_override_redirect(window)?;
+        server_state.set_override_redirect(window, override_redirect);
 
         let window_types = self
             .get_net_wm_window_types(window)?
@@ -917,6 +919,7 @@
         incr => b"INCR" only_if_exists = false,
         xsettings => b"_XSETTINGS_S0" only_if_exists = false,
         xsettings_settings => b"_XSETTINGS_SETTINGS" only_if_exists = false,
+        resource_manager => b"RESOURCE_MANAGER" only_if_exists = false,
         primary => b"PRIMARY" only_if_exists = false,
         primary_targets => b"_primary_targets" only_if_exists = false,
         moveresize => b"_NET_WM_MOVERESIZE" only_if_exists = false,
@@ -1010,7 +1013,7 @@
 #[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 pub struct WmHints {
     pub window_group: Option<x::Window>,
-    pub acquire_input_via_wm: bool,
+    pub accepts_input: bool,
 }
 
 impl From<&[u32]> for WmHints {
@@ -1022,8 +1025,11 @@
             let window = x::Window::new(value[8]);
             ret.window_group = Some(window);
         }
-        if flags.contains(WmHintsFlags::Input) {
-            ret.acquire_input_via_wm = value[1] == 1;
+
+        // if input hint isn't present, set it to true anyways in case the 
client is misbehaving
+        ret.accepts_input = true;
+        if flags.contains(WmHintsFlags::Input) && value[1] == 0 {
+            ret.accepts_input = false;
         }
 
         ret
@@ -1189,7 +1195,9 @@
             match ty {
                 x if x == window_atoms.normal => return WindowRole::Toplevel,
                 x if x == window_atoms.dialog => {
-                    return WindowRole::new_basic(self.has_transient_for && 
motif_no_decor);
+                    return WindowRole::new_basic(
+                        self.has_transient_for && motif_no_decor && 
forced_size,
+                    );
                 }
                 x if x == window_atoms.utility => {
                     return WindowRole::new_basic(motif_no_decor && 
forced_size);
@@ -1429,6 +1437,22 @@
         }
     }
 
+    fn send_take_focus(&mut self, window: x::Window) {
+        let resource_id = self.atoms.wm_take_focus.resource_id();
+        let data = [resource_id, x::CURRENT_TIME, 0, 0, 0];
+        let event = &x::ClientMessageEvent::new(
+            window,
+            self.atoms.wm_protocols,
+            x::ClientMessageData::Data32(data),
+        );
+        
unwrap_or_skip_bad_window_ret!(self.connection.send_and_check_request(&x::SendEvent
 {
+            destination: x::SendEventDest::Window(window),
+            propagate: false,
+            event_mask: x::EventMask::empty(),
+            event,
+        }));
+    }
+
     fn close_window(&mut self, window: x::Window) {
         let cookie = self.connection.send_request(&x::GetProperty {
             window,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/xstate/settings.rs 
new/xwayland-satellite-0.8.3/src/xstate/settings.rs
--- old/xwayland-satellite-0.8.2/src/xstate/settings.rs 2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/src/xstate/settings.rs 2026-09-24 
07:14:09.000000000 +0200
@@ -38,6 +38,7 @@
                 data: &self.settings.as_data(),
             })
             .unwrap();
+        self.update_xft_dpi_resource(self.settings.xft_dpi());
     }
 }
 
@@ -185,4 +186,9 @@
                 last_change_serial: self.serial,
             });
     }
+
+    fn xft_dpi(&self) -> i32 {
+        let setting = self.settings.get(XFT_DPI).unwrap();
+        (setting.value as f64 / DPI_SCALE_FACTOR as f64).round() as i32
+    }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/xstate/tests.rs 
new/xwayland-satellite-0.8.3/src/xstate/tests.rs
--- old/xwayland-satellite-0.8.2/src/xstate/tests.rs    2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/src/xstate/tests.rs    2026-09-24 
07:14:09.000000000 +0200
@@ -473,6 +473,33 @@
         assert_eq!(win.guess_window_role(&win_types), WindowRole::Popup);
     }
 
+    // https://github.com/Supreeeme/xwayland-satellite/issues/470
+    // A DIALOG with TRANSIENT_FOR and no Motif decorations which is resizable
+    // (min_size != max_size) should be a top-level, mirroring the UTILITY fix 
in #383.
+    // Otherwise the popup parent resolves to a hidden WM_CLIENT_LEADER and the
+    // window never appears (e.g. DaVinci Resolve's Project Manager).
+    // Window attributes are taken from the full xprop posted in #470 (DIALOG +
+    // NORMAL window types, _MOTIF_WM_HINTS decorations=0, resizable normal 
hints).
+    #[test]
+    fn davinci_resolve_project_manager() {
+        let win_types = WindowTypes::new();
+        let wm_normal_hints = WmNormalHints::new()
+            .user_pos(978, 270)
+            .user_size(1884, 1620)
+            .min_size(910, 640)
+            .max_size(2880, 1620)
+            .win_gravity(Gravity::Static);
+        let win = WindowRoleHeuristics {
+            has_transient_for: true,
+            motif_wm_hints: Some(motif::Hints::from([0x2_u32, 0x1, 0, 0, 
0].as_slice())),
+            window_types: vec![win_types.dialog, win_types.normal],
+            wm_normal_hints: Some(wm_normal_hints.into()),
+            wm_class: Some("resolve".into()),
+            ..Default::default()
+        };
+        assert_eq!(win.guess_window_role(&win_types), WindowRole::Toplevel);
+    }
+
     // https://github.com/Supreeeme/xwayland-satellite/pull/390
     // With Motif decorations, even a dialog with TRANSIENT_FOR is better 
treated as a top-level
     #[test]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/src/xstate/xresources.rs 
new/xwayland-satellite-0.8.3/src/xstate/xresources.rs
--- old/xwayland-satellite-0.8.2/src/xstate/xresources.rs       1970-01-01 
01:00:00.000000000 +0100
+++ new/xwayland-satellite-0.8.3/src/xstate/xresources.rs       2026-09-24 
07:14:09.000000000 +0200
@@ -0,0 +1,70 @@
+use super::XState;
+use log::warn;
+use xcb::x;
+
+impl XState {
+    pub(super) fn update_xft_dpi_resource(&self, dpi: i32) {
+        // Other clients may replace the resource database so don't cache its 
contents
+        let reply = self
+            .connection
+            .wait_for_reply(self.connection.send_request(&x::GetProperty {
+                delete: false,
+                window: self.root,
+                property: self.atoms.resource_manager,
+                r#type: x::ATOM_STRING,
+                long_offset: 0,
+                long_length: u32::MAX,
+            }))
+            .unwrap();
+
+        let resources = match reply.r#type() {
+            x::ATOM_NONE => &[],
+            x::ATOM_STRING => reply.value::<u8>(),
+            other => {
+                warn!("RESOURCE_MANAGER has unexpected type {other:?}");
+                return;
+            }
+        };
+
+        let xft_dpi = format!("Xft.dpi:\t{dpi}");
+        let mut updated = Vec::with_capacity(resources.len() + xft_dpi.len() + 
1);
+        let mut replaced = false;
+
+        for line in resources.split_inclusive(|byte| *byte == b'\n') {
+            let resource_name = line
+                .iter()
+                .position(|byte| *byte == b':')
+                .map(|separator| line[..separator].trim_ascii());
+            match resource_name {
+                Some(b"Xft.dpi") => {
+                    if !replaced {
+                        updated.extend_from_slice(xft_dpi.as_bytes());
+                        if line.ends_with(b"\n") {
+                            updated.push(b'\n');
+                        }
+                        replaced = true;
+                    }
+                }
+                _ => updated.extend_from_slice(line),
+            }
+        }
+
+        if !replaced {
+            if !updated.is_empty() && !updated.ends_with(b"\n") {
+                updated.push(b'\n');
+            }
+            updated.extend_from_slice(xft_dpi.as_bytes());
+            updated.push(b'\n');
+        }
+
+        self.connection
+            .send_and_check_request(&x::ChangeProperty {
+                window: self.root,
+                mode: x::PropMode::Replace,
+                property: self.atoms.resource_manager,
+                r#type: x::ATOM_STRING,
+                data: &updated,
+            })
+            .unwrap();
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/tests/integration.rs 
new/xwayland-satellite-0.8.3/tests/integration.rs
--- old/xwayland-satellite-0.8.2/tests/integration.rs   2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/tests/integration.rs   2026-09-24 
07:14:09.000000000 +0200
@@ -223,6 +223,21 @@
         window: x::Window,
         surface: testwl::SurfaceId,
     ) {
+        self.configure_and_verify_new_toplevel_with_scale(connection, window, 
surface, 1.0);
+    }
+
+    fn configure_and_verify_new_toplevel_with_scale(
+        &mut self,
+        connection: &mut Connection,
+        window: x::Window,
+        surface: testwl::SurfaceId,
+        scale: f32,
+    ) {
+        let unscaled_geo = connection.get_reply(&x::GetGeometry {
+            drawable: x::Drawable::Window(window),
+        });
+        let (u_width, u_height) = (unscaled_geo.width(), 
unscaled_geo.height());
+
         let data = self.testwl.get_surface_data(surface).unwrap();
         assert!(
             matches!(data.role, Some(testwl::SurfaceRole::Toplevel(_))),
@@ -230,18 +245,22 @@
             data.role
         );
 
-        self.testwl
-            .configure_toplevel(surface, 100, 100, 
vec![xdg_toplevel::State::Activated]);
+        self.testwl.configure_toplevel(
+            surface,
+            u_width as _,
+            u_height as _,
+            vec![xdg_toplevel::State::Activated],
+        );
         self.testwl.focus_toplevel(surface);
         self.wait_and_dispatch();
+
         let geometry = connection.get_reply(&x::GetGeometry {
             drawable: x::Drawable::Window(window),
         });
-
         assert_eq!(geometry.x(), 0);
         assert_eq!(geometry.y(), 0);
-        assert_eq!(geometry.width(), 100);
-        assert_eq!(geometry.height(), 100);
+        assert_eq!(geometry.width(), (u_width as f32 * scale) as _);
+        assert_eq!(geometry.height(), (u_height as f32 * scale) as _);
     }
 
     #[track_caller]
@@ -250,13 +269,23 @@
         connection: &mut Connection,
         window: x::Window,
     ) -> testwl::SurfaceId {
+        self.map_as_toplevel_with_scale(connection, window, 1.0)
+    }
+
+    #[track_caller]
+    fn map_as_toplevel_with_scale(
+        &mut self,
+        connection: &mut Connection,
+        window: x::Window,
+        scale: f32,
+    ) -> testwl::SurfaceId {
         connection.map_window(window);
         self.wait_and_dispatch();
         let surface = self
             .testwl
             .last_created_surface_id()
             .expect("No surface created");
-        self.configure_and_verify_new_toplevel(connection, window, surface);
+        self.configure_and_verify_new_toplevel_with_scale(connection, window, 
surface, scale);
         surface
     }
 
@@ -352,6 +381,7 @@
         incr => b"INCR",
         xsettings => b"_XSETTINGS_S0",
         xsettings_setting => b"_XSETTINGS_SETTINGS",
+        resource_manager => b"RESOURCE_MANAGER",
         moveresize => b"_NET_WM_MOVERESIZE",
     }
 }
@@ -672,6 +702,19 @@
             data: settings,
         }
     }
+
+    fn get_resource_manager(&self) -> Vec<u8> {
+        self.get_reply(&x::GetProperty {
+            delete: false,
+            window: self.root,
+            property: self.atoms.resource_manager,
+            r#type: x::ATOM_STRING,
+            long_offset: 0,
+            long_length: u32::MAX,
+        })
+        .value()
+        .to_vec()
+    }
 }
 
 #[test]
@@ -1986,7 +2029,7 @@
 
     let mut conn = Connection::new(&f.display);
     let window = conn.new_window(conn.root, 0, 0, 200, 200, false);
-    let surface = f.map_as_toplevel(&mut conn, window);
+    let surface = f.map_as_toplevel_with_scale(&mut conn, window, 2.0);
     f.testwl.move_surface_to_output(surface, &output);
     f.testwl.move_pointer_to(surface, 30.0, 40.0);
     f.wait_and_dispatch();
@@ -2150,6 +2193,46 @@
     );
 }
 
+#[test]
+fn resource_manager_scale() {
+    let mut f = Fixture::new_preset(|testwl| {
+        testwl.enable_fractional_scale();
+    });
+    let mut connection = Connection::new(&f.display);
+    f.testwl.enable_xdg_output_manager();
+    let output = f.create_output(0, 0);
+
+    assert_eq!(connection.get_resource_manager(), b"Xft.dpi:\t96\n");
+    connection.set_property(
+        connection.root,
+        x::ATOM_STRING,
+        connection.atoms.resource_manager,
+        b"Xcursor.theme:\tAdwaita\nXft.dpi:\t96\n",
+    );
+
+    let window = connection.new_window(connection.root, 0, 0, 20, 20, false);
+    let surface = f.map_as_toplevel(&mut connection, window);
+    let data = f.testwl.get_surface_data(surface).unwrap();
+    let fractional = data.fractional.as_ref().unwrap();
+
+    fractional.preferred_scale(180); // 1.5 scale
+    f.testwl.move_surface_to_output(surface, &output);
+    f.wait_and_dispatch();
+    assert_eq!(
+        connection.get_resource_manager(),
+        b"Xcursor.theme:\tAdwaita\nXft.dpi:\t144\n"
+    );
+
+    let data = f.testwl.get_surface_data(surface).unwrap();
+    let fractional = data.fractional.as_ref().unwrap();
+    fractional.preferred_scale(300); // 2.5 scale
+    f.wait_and_dispatch();
+    assert_eq!(
+        connection.get_resource_manager(),
+        b"Xcursor.theme:\tAdwaita\nXft.dpi:\t240\n"
+    );
+}
+
 #[test]
 fn xsettings_switch_owner() {
     let f = Fixture::new();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/xwayland-satellite-0.8.2/xwayland-satellite.man 
new/xwayland-satellite-0.8.3/xwayland-satellite.man
--- old/xwayland-satellite-0.8.2/xwayland-satellite.man 2026-07-22 
02:24:52.000000000 +0200
+++ new/xwayland-satellite-0.8.3/xwayland-satellite.man 2026-09-24 
07:14:09.000000000 +0200
@@ -66,6 +66,7 @@
 Force the use of the given rendering API for Glamor acceleration. Valid 
parameters are \fIgl\fR to use OpenGL, \fIes\fR to use GL ES, and \fInone\fR to 
use the shared memory backend. For maximum compatibility with
 .BR Xwayland (1)
 builds without the Glamor backend, the \fInone\fR option is converted to the 
\fI\-shm\fR flag under the hood.
+.TP
 \fB\-help\fR
 Prints a basic usage message and list of accepted flags and returns 0.
 .TP

Reply via email to