Opacity in a reparenting WM - x11

I'm writing a reparenting window manager for X11 (and have asked a number of questions about it here already). Right now, the issue I'm having isn't so much a bug to fix as much as a question on how to implement something.
Applications can request transparency, and if a compositor like xcompmgr or picom is running, they will provide it. However, this doesn't seem to work when I reparent the window; in this case the client window's background just shows a black background behind (maybe the frame window? but the background of that isn't black). I do indicate I have a frame by setting _NET_FRAME_EXTENTS.
What I've tried:
It looks like awesomewm's code for opacity listens to a property notify with a _NET_WM_OPACITY. I don't get any PropertyNotify event when I change opacity of a window, despite selecting SubstructureRedirect|SubstructureNotify|PropertyChange on the root window.

You need to create your frame window with reparenting with depth=32 (i.e.: Made to work with transparency). Since you are already looking at AwesomeWM: It finds the right visual for this at startup and then creates all of its windows this way. That is only necessary since Lua code might want transparency. AFAIR, other WMs look at the program's window bit depth and create their frame window based on that.

Related

Fullscreen borderless window with 'owned' window on-top

I have two OpenGL windows: a main one and a smaller one that is set to be 'owned' by the main one (hWndParent is set in CreateWindowEx, but the WS_CHILD style is not set).
If I then convert my main window to be borderless and the same size as my desktop it will jump in front of the smaller window even though it's owned and that should not be possible (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599%28v=vs.85%29.aspx#owned_windows). This is true even if the smaller window is set to be always-on-top.
On it's own this isn't terrible, but the core issue is that I can still click-through my main window on where the smaller window is, and the smaller window will pop infront. I can go between the two windows endlessly like this by clicking on the main window, then clicking-through the main window.
If I make the main window size 1 pixel less than the full desktop size, none of these issues occur and the windows behave is as expected.
I can't find any documentation that describes this behavior. It is a feature to keep windows from going infront of content (such as a video playing back) that isn't documented, or am I just missing it?
I'll mention I'm not using layered or transparent window here, so I don't think click-through should even be possible?
Thanks
What you experience may very well be a OpenGL implementation bug that's triggered by the heuristic in which the driver switched between "windowed" and "fullscreen" rendering: You see, for OpenGL there's no special "exclusive fullscreen mode" as Direct3D has. Instead a borderless window covering the whole screen, which is not overlapped by foreign windows may trigger a "fullscreen" detection, which may the OpenGL implementation in question make switch to another code path (namely one, where all pixel ownership tests are disabled and the framebuffer flips go directly to the display scanout, bypassing the windowing compositor.
What you do there is so uncommon, that it likely may have slipped through all conformance tests. Having child windows to a OpenGL window is uncommon in the first place and them being floating is even rarer.
If you've got a minimal example showcase, you should probably report it as a bug to the driver vendor. In the meantime I propose a workaround: Make your OpenGL window a child-window to your top level window (will of course require resizing in the toplevel WM_SIZE) and make your floating window another child to the toplevel; the z-order between childs in a parent window is respected and kept. Being a child to a toplevel window should inhibit most heuristics and OpenGL drivers should not loop at the border and size of OpenGL parent windows.

How to stop OpenGL from pausing when the window is out of focus or resizing?

I'm trying to prevent my rendering from stopping when my window is out of focus or resizing. In addition to the resizing, if I resize my window smaller, then bigger again anything that wasn't visible when it was smaller is now black. Is there any way to fix this?
There are really two distinct things going on here. The moving/resizing problem is caused by the windows DefWindowProc function which applications use to handle messages that aren't explicitly handled by the application itself. In the case of moving or resizing, it blocks, creating a new message queue to handle most messages, but there are a few that it will still dispatch to the application's main event queue, like WM_TIMER. You can find lots more information in this answer.
The second issue is that your program only "owns" the pixels inside your window, and only those that are not covered up by other windows. When you make the window smaller, the pixels at the edge need to be overwritten to show the window border or whatever's behind the window. When the window is made bigger, some drivers automatically set the newly acquired pixels to black, while others leave them at whatever they were before (usually part of the window border). The OS doesn't remember if those pixels had some specific color the last time the window was that size, because most of the time the program doesn't care. Instead, windows sends a WM_PAINT message to indicate that the application should redraw the window. Your program should either directly handle this, or use a library like GLFW that abstracts it. In addition, you need to handle resize events by calling glViewport with the new size of the window.

Keep part of a window always visible

It is possible to use the SetWindowPos API on Windows to keep a windows always on top of other windows, and there are many questions on StackOverflow dealing with this.
It is possible to keep only part of a Window always visible? I.e. specify a clipping region inside an existing window, and keep only that part visible?
A use case would be the following (on Windows):
User clicks on icon to run app.
User highlights a portion of the screen to focus on (similar to the Snipping Tool on Windows 7)
The highlighted part of the screen remains always visible, even when other windows/programs are moved over the selected region.
I know the issues that would spring up with having other applications that are also set to being topmost. Just curious if this is even possible?
Even if you change part of your window to be transparent to what's below (with a clipping region) it's still going to take all the mouse clicks, etc. that occur over the transparent part.
Your best bet is to create a new smaller window and make it top-most while hiding the main one.

How to get a print screen of the desktop without any windows or the taskbar?

My application is a Windows Forms one.
I tried using the windows wallpaper, but this depends on the "Fill", "Stretch", "Fit" or "Tile" settings.
I just need the image as it is on the desktop, but including the part "under" the taskbar, because this part is visible in case of transparent taskbar.
Why I need this?
Because I have a tray application which slides from under the taskbar when opening. And I need to set a mask there, so it can't be seen sliding, until it reaches the top of the taskbar. Again, this is only a problem when the taskbar is transparent.
I am not sure if I understood your question correctly. But to me, it seems that you need the image that has created wallpaper. If it seems easier, take a look at registry entries at following location:
HKEY_CURRENT_USER\Control Panel\Desktop
This will give you the path, size, tile/no tile etc. information for the wallpaper.
There is a Win32 function called PaintDesktop you could try but unless I'm misunderstanding things you should be able to just adjust the height of your window so it is never really behind the taskbar...
Why I need this? Because I have a tray application which slides from under the taskbar when opening. And I need to set a mask there, so it can't be seen sliding, until it reaches the top of the taskbar. Again, this is only a problem when the taskbar is transparent.
The problem here is that you're starting the slide up from the bottom of the entire screen, rather than starting from the bottom of the screen's working area (i.e., the top of the taskbar). That's why you're seeing the pop-up window slide up behind a transparent taskbar.
Luckily, the solution is much simpler than obtaining the desktop background and/or doing any type of masking. It's also much faster, and it's always good that your eye candy isn't unnecessarily taxing the user's computer.
All you need to do is determine the coordinates of the screen's working area, which is defined by Windows as the area that can be used by applications, not including the taskbar and other side bars. You can obtain this information easily in WinForms by querying the Screen.PrimaryScreen.WorkingArea property. This will return a Rectangle that corresponds to the primary screen's working area. Since you know that the taskbar is always displayed on the primary screen, this is exactly what you want.
Once you have the coordinates of the primary screen's working area, start your pop-up window's slide from the bottom of that.*
This is a good lesson of why you should always include an explanation of why you want to accomplish something. There's often an even better way that you haven't thought of.
*Of course, I'm ignoring the fact that a user might not have their taskbar positioned at the bottom of the screen. You can put it on either side or even on top. It sounds to me like you haven't considered this in your question, either. If this is an app that you're writing only for yourself or for a controlled environment where you can be sure that no one has their taskbar in non-default positions, that might be OK. But if you're writing software to distribute to a wider audience, you will need to take this into account. The rcWork coordinates will be correct, regardless of where the taskbar is positioned, of course, but you will need to know whether to start the pop-up window's slide from the bottom, the left side, the right side, or the top.

Updating the region behind a resized window

We have a fairly complex GUI, so when certain windows are resized their Redraw() is set to false till the operation is completed. The problem with this is that if the OS "Show window content while dragging" setting is checked, when decreasing the window's size the windows behind it are not repainted. This means I have to force the repaint myself so the remains of the resized window are deleted. I have no problem getting the dimensions of the region that was uncovered. What I'm looking for is best way to cause all windows within that region to repaint their part.
Not being much of a GUI programmer, I can traverse the uncovered region and list the windows in it. Then, I can ask each one of them to repaint its part. But I'm quite certain there has to be a better way to do this...
It is worth mentioning the app is written in PowerBuilder. This means I can call whatever Win32 function I'd like, but have limited control over the GUI behavior and the message handling. If there's a better way to prevent the window's content resize from being visible, or there's a way to make a non-redrawn window clean after itself, I'd love to hear it (just have the limitations above in mind).
I'm curious what version of PowerBuilder you are working in? I do resizing all the time and never run into issues like you are describing.
Maybe you can lay out some more detail on why you need to set your redraws to false within the PowerBuilder environment.
Hope I can help.

Resources