I'm following the Vulkan Tutorial and the section Window Surface says that on Windows a VkSurfaceKHR object is created using the following code:
VkWin32SurfaceCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.hwnd = glfwGetWin32Window(window);
createInfo.hinstance = GetModuleHandle(nullptr);
if (vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface) != VK_SUCCESS) {
throw std::runtime_error("failed to create window surface!");
}
But we never specify the extents of the surface in the createInfo object.
However calling the vkGetPhysicalDeviceSurfaceCapabilitiesKHR function returns a VkSurfaceCapabilitiesKHR object which has a currentExtent field which according to the documentation is
the current width and height of the surface, or the special value (0xFFFFFFFF, 0xFFFFFFFF) indicating that the surface size will be determined by the extent of a swapchain targeting the surface.
So in the special case that currentExtent equals (0xFFFFFFFF, 0xFFFFFFFF) we know that the size of the surface is determined by the swapchain targeting the surface, but in all other cases it seems that the surface already has a size originating from somewhere else and we are expected to match the extents of the swapchain to that size.
So where does the size of the surface come from when it's not being determined by the swapchain?
On Windows, the initial extents of the surface are equal to the width and height values you set when creating the window (minus window borders, menus, etc.).
The extents value returned by vkGetPhysicalDeviceSurfaceCapabilitiesKHR also updates automatically when the window is resized by the user (on Windows).
It is also important to note that on different platforms, max, min, and current extents behave differently. On Windows, the output surface must always be equal to the paintable window size, so they will all be equal.
Related
I'm creating a multi-window application (cross-platform (X11, macOS, Windows), unspecified window manager), where each window corresponds to a document.
When creating a new document (and thus window), the window manager should be free to put the window wherever it finds suitable.
However, if the user manually moves the window to some location, this location should be saved along with the document (so on re-opening the document, it will be at exactly the place it was last saved).
The (initial) window size is fixed.
In order to find out the current position, I can either use wm geometry or winfo geometry, which both return slightly different results (the former with decoration (like border and menu), the latter without).
As I understand it, I need the result of wm geometry if I would like to restore the position of the window.
However, when I create an initial window and resize it, winfo geometry returns the correct position (but without the decoration), whereas wm geometry does not.
# hide the default window
wm withdraw .
toplevel .my
wm geometry .my 200x100
# the following prints "1x1+0+0" for both geometries
puts "[wm geometry .my] [winfo geometry .my]"
raise .my
# this prints something like "200x100+0+0 200x100+860+542"
puts "[wm geometry .my] [winfo geometry .my]"
If I manually move the window and then call [wm geometry .my] again, it now correctly reports whatever position the window is at.
So my question is:
Is there a way to get the window position (as set by the window manager) after I resized the window using wm geometry ${w}x${h}?
Alternatively, is there a way to find out (from the window itself) whether the user has moved it to some other place? (so I can save the position as "undefined, let the WM do their thing").
Ideally, such a solution would handle the case where the user to manually moved the window to the +0+0 position differently from the case where the window was not moved at all.
I'm especially interested in getting this information without having to bind to the <<Configure>> (or some other) event, in order to detect whether the user touched the window.
sidenote: setting the window dimensions
I know that I can set the window dimensions with both wm geometry ${w}x${h} and when creating the window with toplevel .wm -width $w -height $h.
When doing the latter, wm geometry returns the correct window position, but what are there any other differences between the two?
I think a more extensive use of winfo is what you need:
https://www.tcl.tk/man/tcl8.6/TkCmd/winfo.htm
set _x [winfo rootx .my]
The command above returns the X coord of the upper-left corner
winfo rooty .my
Same as before, returns the Y coord of the upper-left corner
winfo width .my
winfo height .my
Same for these self-explaining commands.
You can save in real time the position and size of any window, to restore later on re-open.
Say you have a form that you can expand to the left to show additional controls:
Collapsed:
Expanded:
The simplest way to achieve this in Delphi is to use alRight as the primary anchor for all controls (instead of alLeft) and then simply adjust the width and X coordinate of the form. Either you can set the Width and Left properties individually, or you can use a function that sets them simultaneously, like
if FCollapsed then
SetWindowPos(Handle, 0, Left - Width, Top, 2 * Width, Height, 0)
else
SetWindowPos(Handle, 0, Left + Width div 2, Top, Width div 2, Height, 0)
The problem is that there is quite noticeable flickering in the always-visible part of the form (in this example, the buttons) while expanding or collapsing. Try it yourself!
It is possible for the operating system to resize the form to the left without any flickering at all -- just grab the left edge of the form using the mouse and drag the mouse to the left or right -- but I am unable to find any function in the Windows API that exposes this kind of resizing.
I have tried to use several different Windows API functions to resize and reposition the form, tried their various parameters (for instance, the SWP_* flags), tried LockWindowUpdate, WM_SETREDRAW, TForm.DoubleBuffered etc. to no avail. I also examined the possibility to use the WM_SYSCOMMAND SC_SIZE approach.
I am not yet sure if the problem lies at the OS level or the VCL level.
Any suggestions?
Edit: I am very surprised to see that this Q received close votes. Let me try to clarify:
Create a new VCL forms application.
Add a few buttons to the right side of the main form and a memo to the left. Set Anchors to [alTop, alRight] on all controls. On the OnClick handler of the buttons, add the following code:
if FCollapsed then
SetWindowPos(Handle, 0, Left - Width, Top, 2 * Width, Height, 0)
else
SetWindowPos(Handle, 0, Left + Width div 2, Top, Width div 2, Height, 0);
FCollapsed := not FCollapsed;
where FCollapsed is private boolean field of the form (initialized to false).
Now, click the buttons repeatedly. (Or give one of them keyboard focus and hold the Enter key for a few seconds.) You will probably notice that the region with the buttons on your monitor will not display a perfect still image, but will flicker. In addition, you might actually see 'ghosts' of the buttons to the left of the actual column of buttons.
I am unable to capture this millisecond flickering using screen capture, so instead I used a digital camera to record my screen:
https://privat.rejbrand.se/VCLFormExpandFlicker.mp4
In this video clip, it is apparent that the column of buttons isn't a static image on the screen; instead, for a few milliseconds each time the form is resized, this region is something else than it should be. It is equally apparent that there is a 'ghost' column of buttons to the left.
My question is if there is any reasonably simple way to get rid of these visual artefacts (that at least to me are very visible even if you expand/collapse the form a single time).
On my Windows 10/Delphi 10.1 computer at work, the form is resized in a perfect manner when I drag its left-most edge using the mouse: the unaffected client area of the form is perfectly static on the monitor. However, on my Windows 7/Delphi 2009 PC at home, I do see that there is a lot of repositioning going on when I do this.
I can provide some insight about why you see ghost images of the other half of your UI and possibly a way to stop it. The ghost image indicates that someone is copying your client area pixels (and copying them to the wrong place, always flush-left in your window) before you have a chance to redraw them with the correct pixels.
There are likely two different, overlapping sources of these ghost pixels.
The first layer applies to all Windows OSes and comes from a BitBlt inside SetWindowPos. You can get rid of that BitBlt in several ways. You can create your own custom implementation of WM_NCCALCSIZE to tell Windows to blit nothing (or to blit one pixel on top of itself), or alternately you can intercept WM_WINDOWPOSCHANGING (first passing it onto DefWindowProc) and set WINDOWPOS.flags |= SWP_NOCOPYBITS, which disables the BitBlt inside the internal call to SetWindowPos() that Windows makes during window resizing. This has the same eventual effect of skipping the BitBlt.
However, Windows 8/10 aero adds another, more troublesome layer. Apps now draw into an offscreen buffer which is then composited by the new, evil DWM.exe window manager. And it turns out DWM.exe will sometimes do its own BitBlt type operation on top of the one already done by the legacy XP/Vista/7 code. And stopping DWM from doing its blit is much harder; so far I have not seen any complete solutions.
For sample code that will break through the XP/Vista/7 layer and at least improve the performance of the 8/10 layer, please see:
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?
Since you have multiple child windows, the situation is even a little more complicated. The BitBlt type operations I mentioned above happen on your whole top-level window as a whole (they treat the window as one set of pixels regardless of how many windows are underneath, and regardless of CLIPCHILDREN). But you need to have windows move atomically so that on the next redraw they are all positioned correctly. You may find BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos useful for that (but only go there if the above tricks do not work).
I am trying to export a plot generated by my program in the form of a bitmap. No problem with creating a bitmap in memory (with CreateDIBSection) and saving it on the disk (using GDI+). To draw I have to use device context, and the only one that is easily available is compatible with the screen. So I create a compatible dc, select the bitmap I already created into this device context and I am ready to draw and print into the bitmap. And it works - but it gives me no control over the size of the plot (note: size of the plot, not size of the bitmap). If I understand correctly what is happening mapping modes follow DPI of the screen DC which in turn means size of the plot (and text I put on the plot) is different on different computers.
Is there any way of changing the DPI resolution for the device context? Or perhaps there exist a better way of doing what I am trying to do? Perfect solution would be to ask user for the pixel bitmap size and be able to draw a plot that nicely fits the bitmap.
You don't have to use device context to draw now that you already use Gdiplus over GDI. You just associate your Gdiplus::Graphics object with a Gdiplus::Bitmap instead of HDC. Units and transformations let alone bitmap size are all independent of the device. Hope that helps.
Gdiplus::Bitmap bitmap( L"miranda_kerr.png" ); // draw over existing
Gdiplus::Graphics graphics( &bitmap );
Gdiplus::Pen pen( Gdiplus::Color(255,0,0));
Gdiplus::Status status = graphics.DrawLine( &pen, 20, 20, 100, 500 );
//...
I have a script that positions the popup at the bottom right corner of the users screen every time. However, IE8 could care less about the fact that there is more to the window than the viewport. How do I get the size of that in IE8?
var popUpWidth = window.outerWidth; // does not work in IE8!
var popUpHeight = window.outerHeight; // does not work in IE8!
IE8 doesn't have the outerWidth / outerHeight property, try instead:
document.documentElement.clientHeight;
document.documentElement.clientWidth;
Here's an example http://james.padolsey.com/javascript/get-document-height-cross-browser/
Set the window to a given size. Obtain the size of the client window. This will be smaller by the amount of window chrome. Use the difference to calculate the window size for any client size.
The initial size is completely arbitrary but the current client size plus an optional fudge factor will cause the least change on screen.
My main NSWindow contains UI restricted to some size range, otherwise it can get corrupt. I restrict the window to a size-range using
[myWindow setContentsMaxSize:maxSize]
[myWindow setContentsMinSize:minSize]
This works fine for user dragging of the edges or size-box.
When the user presses "fullscreen" button, Lion starts an animation that will
Shrink the window below its current size,
in several steps, increase its size until it reaches the full-screen representation size.
If the window started in its minimal size, this animation will shrink it BELOW the defined minimal size, and will corrupt my UI beyond repair (user needs to relaunch the app). My views are receiving setFrameSize: with unsupported size.
My questions
Can this be considered a Cocoa bug?
Am I doing something wrong in my view hierarchy?
Can I somehow prevent the corruption, without replacing the OS standard animation for full-screen?
Why doesn't the standard animation base on a "snapshot" of the window contents, instead of
live-resizing of the whole view-hierarchy throughout the animation? This is surely not efficient.
Is there a simple way to apply another standard transition that will
be non-destructive for me?
Can someone "spare" a few lines of code that will do a simple linear resizing animation that will NOT go below minimum?
Thanks.!
I've also investigated fullscreen animation behaviour and here is how it works:
It is also based on taking snapshots of window's content, but with some improvements. It takes several snapshots on some control points: 512, 1024, 2048 and so on.
In my case to enter full screen 2560x1440, my 400 pixels wide window took 512 pixels snapshot, then 1024 and then 2560 wide snapshot. I don't know whether this behaviour is default for all cases, but this is the result of my own investigation.
On the issue with setting min/max window size:
Minimal window size set up in Interface Builder works for me, but max constraints not. I'm currently working on it and this documented method should work for you:
Place this code into your window delegate.
static const NSSize kWindowMinSize = {100, 100};
static const NSSize kWindowMaxSize = {100500, 100500};
...
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
frameSize.width = MAX(kWindowMinSize.width, MIN(kWindowMaxSize.width, frameSize.width));
frameSize.height = MAX(kWindowMinSize.height, MIN(kWindowMaxSize.height, frameSize.height));
return frameSize;
}
Hope this will help you!