fia0 / enkei

A wayland wallpaper tool with support for GNOME dynamic wallpapers
https://enkei.spacesnek.rocks
GNU General Public License v3.0
24 stars 1 forks source link

Moving window to another display does not work as expected #1

Closed emirror-de closed 2 years ago

emirror-de commented 2 years ago

Hi there, thanks for this great project. I ran into a problem, wondering if there is an easy fix for it:

Trying to move a window from one monitor to another in a multi monitor setup does not work. However, when there are windows opened on both monitors, it works. I am using sway as the compositor.

Best regards, Lewin

fia0 commented 2 years ago

Hi Lewin, can you specify what you mean by "move a window" in this context? The opened (enkei) windows should be automatically spanned over the connected outputs and you should not be able to move them manually. For general information; can you send me the version infos of sway and enkei?

$ sway --version
$ enkei --version

The case of abnormal behaviour, if no windows are open on one monitor, I currently can't reproduce myself with sway on my local system. Can you perhaps describe your monitor setup and the order of actions to reproduce more in-detail?

emirror-de commented 2 years ago

Thanks for your response, sorry for missing context and bad explanation.

So first of all, the versions: Sway: sway version 1.6-5865af75 (Nov 19 2021, branch 'master') enkei: enkei 0.1.1

Okay, so in general, enkei does its job, meaning the background is displayed correct on both monitors. It is also not possible to move the enkei window anywhere.

In Sway, it is possible to move an open window (e.g. a terminal) by pressing the Modifier key (e.g the meta key) and holding down the left mouse button, dragging it where you want it to be placed (indicated by a blue transparent while dragging). With this method, Mod+LeftMous, it is also possible to move an open window to another monitor by drag.

Example: I do have two monitors next to each other mon1 and mon2. enkei is running. A terminal is open on mon1, mon2 does not have any windows on it. I want to move the terminal to mon2 by using Mod+LeftMouse dragging. It does not work. I do not get the blue transparent on the second monitor and if I release the mouse button, the terminal is not moved to mon2. When using swaybg instead of enkei, it is possible to move the terminal as described.

Additional scenario: Both mon1 and mon2 contain a terminal window. enkei is running. I want to drag the terminal from mon1 to mon2. While doing, the blue transparent is visible on mon2 and the terminal gets also placed on mon2 when the mouse button is released.

Hope that this explanation is a bit clearer than the small first one? :) It seems to me like there is a missing property in the enkei windows to make sway recognize them when they are the only window opened on a monitor?

fia0 commented 2 years ago

The clarification helped a lot, I can reproduce this issue now :D I think I found some reason why this problem occurs, in this tool I use gtk since I did not want to handle all wayland protocols manually, part of the problem seems to lie in exactly this. In swaybg the setup for their surfaces look almost identical to the setup in enkei:

swaybg:

    output->surface = wl_compositor_create_surface(output->state->compositor);
    assert(output->surface);

    // Empty input region
    struct wl_region *input_region =
        wl_compositor_create_region(output->state->compositor);
    assert(input_region);
    wl_surface_set_input_region(output->surface, input_region);
    wl_region_destroy(input_region);

    output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
            output->state->layer_shell, output->surface, output->wl_output,
            ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper");
    assert(output->layer_surface);

    zwlr_layer_surface_v1_set_size(output->layer_surface, 0, 0);
    zwlr_layer_surface_v1_set_anchor(output->layer_surface,
            ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
            ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
            ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
            ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
    zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
    zwlr_layer_surface_v1_add_listener(output->layer_surface,
            &layer_surface_listener, output);
    wl_surface_commit(output->surface);
}

enkei:

   let window = gtk::Window::new(gtk::WindowType::Toplevel);
    app.add_window(&window);

    gls::init_for_window(&window);
    // Push other windows out of the way
    gls::set_exclusive_zone(&window, -1);
    // Anchors are if the window is pinned to each edge of the output
    gls::set_margin(&window, gls::Edge::Left, 0);
    gls::set_margin(&window, gls::Edge::Right, 0);
    gls::set_margin(&window, gls::Edge::Top, 0);
    gls::set_margin(&window, gls::Edge::Bottom, 0);
    gls::set_layer(&window, gls::Layer::Background);
    gls::set_monitor(&window, monitor);

    // Set up a widget
    window.add(img);
    window.show_all();

It could be in the way that swaybg declares the input as empty they are able to handle it like so, and gdk seems to set this to the cairo region size (https://github.com/GNOME/gtk/blob/50e4ca8593d12b2de76e4d092d34ec7a1655ede8/gdk/wayland/gdksurface-wayland.c#L1274-L1296) if not explicitly set to null. In gtk/gdk there does not seem to be a straightforward to do this from the library level I'm operating here.

I experimented with swaybg to omit this explicit emptying of the input region and it observes the same behavior. So perhaps this could be the reason after all, but I don't see a quick way to reproduce this explicit setting of the input region in enkei right now. I'll investigate this problem further tomorrow and see if some workaround exists or I'm just missing something right now.

btw: Thanks for raising this issue, I simply never used this feature so I weren't aware of this^^

fia0 commented 2 years ago

Hey, so I got around to have a deeper look into this problem. I just experimented with wayland-client and created a small mockup example and this confirms the suspicion of the empty input region, as this works as expected. Though this makes it hard to deal with this in gtk.

Though this; and other annoyances with gtk; make me think gtk is simply not well suited for this kind of integration outside of "normal" GUI applications. I played before with the thought to re-implement enkei with plain wayland protocols, I will probably continue doing this instead of continuing to work around gtk. I'm afraid this means that for now this bug will persist. I'm sorry for this inconvenience.

If you or anyone reading have a suggestion on how to properly handle this issue with gtk please drop a comment. An idea could be (https://gtk-rs.org/gtk3-rs/stable/latest/docs/gdk/struct.Window.html#method.shape_combine_region) but retrieving this over the Screen interface does not seem to have an effect similar to input regions in wayland-client.

Another point to start: https://gitlab.gnome.org/GNOME/gtk/-/blob/master/gdk/wayland/gdksurface-wayland.c This is where interesting input_region related activities are happening.

fia0 commented 2 years ago

Hey @emirror-de,

so back to this issue. I just released a new version v0.9.0 which fixes this issue.. by being a complete rewrite of enkei. Things behave mostly the same, though the rendering changed to being OpenGL based now instead of copying gtk image buffers around.

I'll close this issue for now, but if you find any other troubles you're very welcome to open a new issue :)

emirror-de commented 2 years ago

Awesome, works perfectly fine! Thanks for this great update!