Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering broken - follow up #43

Closed
zdenek-biberle opened this issue Aug 7, 2018 · 13 comments
Closed

Rendering broken - follow up #43

zdenek-biberle opened this issue Aug 7, 2018 · 13 comments

Comments

@zdenek-biberle
Copy link

zdenek-biberle commented Aug 7, 2018

I did some more digging on the issue mentioned in #42 and I came to some interesting conclusions.

First of all, I checked the window tree of Reaper's FX window:

xwininfo: Window id: 0x4400c89 "FX: Track 1"

  Root window id: 0x701 (the root window) (has no name)
  Parent window id: 0x1a00832 (has no name)
     2 children:
     0x4400c88 (has no name): ()  198x346+252+74  +1580+197
        1 child:
        0x5000003 "LinVst": ("lin-vst-server.exe" "Wine")  198x346+1280+0  +2860+197
     0x4400c8a (has no name): ()  1x1+-1+-1  +1327+122

Clearly the window is there, so reparenting has worked fine. But notice its position - it's at +1280+0, but it should be at +0+0. This explains why I can't see the GUI - it's just hidden too far to the right.

Now, why 1280? That's quite a nice number, it's not some garbage uninitialized value that got accidentally picked up by X11 as a coordinate.

Well, this is where it gets fun. I've got a screen to the left of the primary screen that's 1280x1024. When I disable this screen, the window is correctly positioned at +0+0 and the GUI works fine!

So you'd think that if I set my left screen to be the primary one, then I should have no problems, right? Wrong. The LinVst windows is now at +0+56. Not as bad as previously, but still bad.

See, the left screen is 1280x1024, the right one is 1920x1080 and they are aligned at the bottom. This means that the left screen is at +0+56 and the right screen is at +1280+0.

So I am thinking that LinVst's window position is set to whatever the position of the primary screen is. Now the question is, why?

I attempted querying the window's position from the client side using XGetGeometry and it appears that the call to openGUI is causing this. I have no idea why, though - could this be some sort of Wine trickery so that the window coordinates are relative to the top left of the primary screen? Is that how it works on Windows?

Anyway, I tried moving the LinVst window to +0+0 after the call to openGUI with XMoveResizeWindow and it seems to have worked, but I don't think that's the correct solution.

@AxxlForce, could this be the cause of your problems as well? What's your screen setup?

@osxmidi
Copy link
Owner

osxmidi commented Aug 8, 2018

Basically for the embedded LinVst version, Reaper (or the host) sends a call to the vst asking it's window size and LinVst passes that on to the vst and then sends the vst window size back to Reaper.

Then Reaper opens a plugin window corresponding to that size and LinVst reparents the vst's (Wine) window into it.

So, LinVst isn't involved that much and if there is a system problem due to more than one monitor or something that a particular window manager might be doing then it might result in something being displayed wrongly and LinVst can't do much about it.

Maybe the host can do something about it (multiple monitor compatibility etc) because it controls the windows that LinVst reparents the Wine window into but the system itself might need to be configured and/or the system might even have incompatibilities ie drivers/window managers/ X11/Gtk etc and how they interact and are setup.

The LinVst standalone version puts up it's own window that doesn't depend on Reaper or the host.

@zdenek-biberle
Copy link
Author

So, LinVst isn't involved that much

I don't think that's the case - LinVst attempts to move the child window to +0+0, but that gets overridden when openGUI gets called, which, if I'm reading the source correctly, causes ShowWindow to be called on the server side. At this point, whatever happens is some Wine/Windows magic that positions the window.

LinVst needs to make sure that the child is at +0+0. As I've said, moving the window after the call to openGUI works. But again, I don't think that's the correct way to do it.

a system problem due to more than one monitor

I wouldn't say that this is a system problem. Rather, it's just how Wine works (I think).

something that a particular window manager might be doing

I guess that a WM could be doing some funny positioning even after the window has been reparented, although I don't think that it does so in my case. But I'll try a couple of different WMs, just to be sure.

Maybe the host can do something about it

Probably not - it just gives the VST a window, it doesn't (and shouldn't) care that you're reparenting a different window into it with weird coordinates.

The LinVst standalone version puts up it's own window that doesn't depend on Reaper or the host.

Yes, and that works fine.

@osxmidi
Copy link
Owner

osxmidi commented Aug 8, 2018

The Wine window gets moved to 0,0 relative to the Reaper/Host vst window.

Reaper provides a window and LinVst reparents the Wine window with 0,0 coords into it and it becomes the child window of Reapers provided window.

The 0,0 is the offset that the Wine window will have from the provided Reaper vst window (which is the parent window), so if 0,0 was changed to 10,10 then it would produce an offset and the Wine window wouldn't look right when it was reparented into Reapers (parent) window.

Like, for the Tracktion version I needed to have a window manager title bar offset (because of the way they do things) and the Wine window is moved to an offset that is the same as the window manager's title bar height and width.

That's from what I remember about the GUI code, which was a while back.

I havn't had anyone report any embedded window problems and some users are using Arch, and I can't reproduce any problems but I'm using only one monitor.

I've had various window managers with various distros and I can't reproduce any GUI problems, so to me it could be a system problem of some sort, maybe a library, maybe something about Wine on the system, multiple monitors could cause some trouble, hard to tell.

@zdenek-biberle
Copy link
Author

The Wine window gets moved to 0,0 relative to the Reaper/Host vst window.

Reaper provides a window and LinVst reparents the Wine window with 0,0 coords into it and it becomes the child window of Reapers provided window.

The 0,0 is the offset that the Wine window will have from the provided Reaper vst window (which is the parent window), so if 0,0 was changed to 10,10 then it would produce an offset and the Wine window wouldn't look right when it was reparented into Reapers (parent) window.

I understand all of that. However, that's not actually what happens. I put a few XGetGeometry calls into the client's effEditOpen handler to see how the position of the child window changes over time and this is the result:

There's two questions to ask here:

  • Why does the child window start at +1280+0?
  • Why does its position revert to +1280+0 when openGUI (which, AFAICT, calls ShowWindow and UpdateWindow) get called?

I guess that the answer to the second question is easy - wine, for some reason, keeps its own window positions independent from X11. And when ShowWindow gets called, it moves the window to this position, just to be sure.

The first question is not that easy. But my best guess is that wine follows the way screen coordinates work on Windows. I found this document, which clearly states:

The primary monitor contains the origin (0,0). This is for compatibility with existing applications that expect a monitor with an origin. However, the primary monitor does not have to be in the upper left of the virtual screen.

It also provides this handy picture:

https://docs.microsoft.com/en-us/windows/desktop/gdi/images/multimon-1.png

This means that when you create a window with CreateWindow(Ex), the coordinates have to be translated between Windows-style coordinates and X11-style coordinates (ie. origin being in the top left corner of the entire area). In my case, that means adding +1280+0 to the position and so the window ends up at +1280+0.

What's the solution to this? I don't know. As I've tested, moving the window to +0+0 with XMoveWindow after openGUI is called seems to work, but after tracing how the position changes, I wouldn't really trust it to keep working at all times.

Maybe creating the window with WS_CHILD could help?

Finally, I think that you could query the X11 position of the window right after creating it with CreateWindowEx and then subtract that from its Window position. Ie. create the window at +0+0, query the X coordinates +1280+0 and then move the window to -1280+0 to compensate.

Although that sounds a bit hacky.

I'll try something out when I get some time and see how it goes.

Like, for the Tracktion version I needed to have a window manager title bar offset (because of the way they do things) and the Wine window is moved to an offset that is the same as the window manager's title bar height and width.

Yeah, I noticed that. In my case the window would end up at +1280+0 + whatever the title bar offset is and so it wouldn't look right.

I havn't had anyone report any embedded window problems and some users are using Arch, and I can't reproduce any problems but I'm using only one monitor.

Well, not only do you need multiple screens, you also need the primary to not have its top left corner at +0+0. And I'm pretty sure that the most common multi monitor setup is two 1920x1080 screens side by side, with the left one being the primary one, which wouldn't have this problem.

I've had various window managers with various distros and I can't reproduce any GUI problems

Just to be sure, I tried Xfwm4, Openbox, awesome and i3 and had exactly the same issue with all of them.

to me it could be a system problem of some sort, maybe a library, maybe something about Wine on the system, multiple monitors could cause some trouble, hard to tell.

Well, after seeing the results above, I'm convinced that my guess is very close to the actual issue. I'll let you know when I have more information.

@osxmidi
Copy link
Owner

osxmidi commented Aug 9, 2018

The Wine window is a X11 window on the Linux side which is the linvst.so side.
linvst.so deals with the Wine X11 window and it's position and the position is tracked via XTranslateCoordinates in ConfigureNotify via the window manager and LinVst needs the Allow the window manager to control the windows option enabled in winecfg (which is the default).

On the Wine side which is the lin-vst-server.exe side, the Wine window is dealt with by windows calls ie SetWindowPos, ShowWindow, UpdateWindow etc and these need to be called by the Linux linvst.so side via showgui opengui hidegui etc so that the Linux side and Wine side are in sync.

If the window position is altered or offset from 0,0 on the Wine side via SetWindowPos then it will have an effect on the Linux side and the Linux vst plugin display will be at whatever the offset is, so setting an offset of 10, 10 via SetWindowPos will result in a 10,10 offset from the vst plugin window (Linux parent window) origin.

So, LinVst only deals with the Linux vst plugin window (the Linux DAW's vst plugin X11 window) and offsets within that window by reparenting the Wine X11 window into it and the offset position is set by SetWindowPos 0, 0 which means no offset relative to the reparenting of the Linux DAW's vst plugin X11 window and the Wine X11 window.

The Wine SetWindowPos 0, 0 is positioning the Linux Wine X11 window at 0, 0.

After the reparenting the Linux Wine X11 window is tracked by the window manager and is done by XTranslateCoordinates in ConfigureNotify and this is needed for mouse/window position sync.

If the (Wine) X11 window was at 0, 0 and then reparented into a window at say 500, 500 then the (now child) X11 window isn't at 0, 0 anymore it's at 500, 500 but it's still at 0, 0 relative to the parent window and wherever the parent window moves to the child moves to and that's done by the window manager tracking XTranslateCoordinates in ConfigureNotify.

If the (Wine) X11 window was at 10, 10 and then reparented into a window at say 500, 500 then the (now child) X11 window isn't at 0, 0 anymore it's at 510, 510 and is offset by 10, 10 in the parent window (the Linux DAW's vst X11 window).

What Wine may be doing with multiple monitor setups I don't know, because it might involve X11 multi monitor setups ie xorg.conf.

@zdenek-biberle
Copy link
Author

If the window position is altered or offset from 0,0 on the Wine side via SetWindowPos then it will have an effect on the Linux side and the Linux vst plugin display will be at whatever the offset is, so setting an offset of 10, 10 via SetWindowPos will result in a 10,10 offset from the vst plugin window (Linux parent window) origin.

The Wine SetWindowPos 0, 0 is positioning the Linux Wine X11 window at 0, 0.

No, it's not.

I had to look this up in the Wine source code. The X11 driver uses these two functions to translate back and forth between Windows-style virtual screen coordinates (ie. +0+0 being at the top left of the primary screen) and X11-style root window coordinates (ie. +0+0 being the top left of the entire display area, possibly offscreen). These are used in multiple places in the driver code, one example being the sync_window_position function, which is apparently used to "Synchronize the X window position with the Windows one".

So whenever you set window coordinates through Windows function (eg. CreateWindowEx, MoveWindow, SetWindowPos etc.) to +0+0, the X11 position doesn't get set to +0+0 - it gets set to +0+0 + the position of the primary screen relative to the root window. In many cases that's still +0+0, but not always. In my case, it's +1280+0.

Wine doesn't expect the window to be a child of an already existing X11 window, and so it treats it as if it were a top-level window and translates the coordinates accordingly.

And this is the root of the problem - the coordinate systems differ between X11 and Windows (wine) and the translation between them causes issues in this case.

I previously thought that creating the child window with the WS_CHILD flag could maybe fix this, but I'm not seeing that in the code - maybe WS_CHILD windows are not actual X11 windows? I don't know yet, I'll have to look deeper into it.

What Wine may be doing with multiple monitor setups I don't know, because it might involve X11 multi monitor setups ie xorg.conf.

It's not really a multimonitor issues, I'm pretty sure you could setup X11 so that your root window was bigger than your screen and your screen was not positioned at +0+0 and it would cause the same issues.

@osxmidi
Copy link
Owner

osxmidi commented Aug 10, 2018

That post was for a single display/monitor.

As I said, I havn't done any testing with multiple monitors.

So, I tried setting up multiple monitors with Ubuntu Studio 17.10 and a Radeon HD 6670/7670 on an i7 with Wine Staging 3.13.

This is the main monitor

https://drive.google.com/uc?export=download&id=1ykuNa5zoPOHdDDVVLBNQhOyN6M-dy9Ag

and this is the extended monitor

https://drive.google.com/uc?export=download&id=1kHTVzAcLaF8znOCN7UBw7-_y_mMUxqS0

and as far as I can tell the embedded vst wine window positions are ok and also the mouse/menu positions are ok in the main monitor/display and the extended monitor/display.

@zdenek-biberle
Copy link
Author

That post was for a single display/monitor.

Oh, sorry, I didn't catch that.

Anyway, thank you for trying it out with multiple monitors.

How have you got them set up? Side by side? Did you set up the right one as the primary one?

@osxmidi
Copy link
Owner

osxmidi commented Aug 10, 2018

The monitor with Reaper (and the Ubuntu Studio menu bar at the top) in it was the primary.

@zdenek-biberle
Copy link
Author

That doesn't matter. What matters is if the primary screen is positioned somewhere else other than +0+0 of the root window. If you've got the screens side by side, the easiest way to achieve that is by setting the right one to be primary.

@osxmidi
Copy link
Owner

osxmidi commented Aug 10, 2018

I made the other one the primary and there is a problem probably due to the offset.

I can get around it by making the other one the primary, so it's not impossible to get working but if someone has whatever primary setup for some reason then they might run into problems.

I'll look into it when I can get around to it.

@osxmidi
Copy link
Owner

osxmidi commented Aug 10, 2018

I've made some changes to the code, it seems to work with multiple monitors.

@zdenek-biberle
Copy link
Author

zdenek-biberle commented Aug 10, 2018

I can get around it by making the other one the primary, so it's not impossible to get working but if someone has whatever primary setup for some reason then they might run into problems.

Well yeah, that's what I've been saying the whole time.

I've made some changes to the code, it seems to work with multiple monitors.

Thank you. Using GetSystemMetrics is much more elegant than whatever hacky solution I was thinking about. I'll try it out when I get home.

Just one minor detail: is it really necessary to have the if(GetSystemMetrics(SM_CMONITORS) > 1) condition there? Because, as I've already stated, this issue may not necessarily come up only when you use multiple monitors. I would just remove the condition and the else branch and just keep the new calls to SetWindowPos.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants