Why this BitBlt example doesn't work anymore? - c

I'm currently getting back to some Windows Programming using Petzold's book (5th edition).
I compiled the following example using BitBlt and it doesn't work as it is supposed to.
It should copy the Window's icon of (CxSource, CySource) size and replicate it on the whole window's surface.
What happens, in reality, using Windows 7 is that the bitmap below the window gets sourced and copied into the drawing surface i.e. hdcClient.
I don't understand why it behaves like this knowing that it's clear the DC passed to BitBlt is hdcWindow, which refers to a device context obtained via a GetWindowDC(hwnd) of the current application.
I first thought it was due to the fact the transparency mode is enabled by default, but deactivating it doesn't change anything. BitBlt seems to always take the surface below the application Window!
I don't get it! :)
Anyone knows why it works that way and how to fix it?

Making screenshots with BitBlt() did not exactly get any easier since the addition of the DWM (Desktop Window Manager, aka Aero). Petzold's sample code suffers from a subtle timing issue, it is making the screenshot too soon. It does so while Aero is still busy animating the frame, fading it into view. So you see what is behind the window, possibly already partly faded depending on how quickly the first WM_PAINT message is generated.
You can easily fix it by disabling the effect:
#include <windows.h>
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
And after the CreateWindow() call:
BOOL disabled = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, &disabled, sizeof(disabled));
Another tricky detail is that the first BitBlt matters, the DWM returns a cached copy afterwards that is not correctly invalidated by the animation.
This gets grittier when you need a screenshot of a window that belongs to another process. But that was already an issue before Aero, you had to wait long enough to ensure that the window was fully painted. Notable perhaps is the perf of BitBlt(), it gets bogged-down noticeably by having to do job of composing the final image from the window back-buffers. Lots of questions about that at SO, without happy answers.

It is not supposed to copy the windows icon, it is supposed to copy the windows titlebar part where the icon is located.
There are some issues with this (now 20 year old code):
GetSystemMetrics values cannot be used for window related dimensions anymore since GetSystemMetrics returns the classic sizes, not the Visual Style sizes.
Depending on the Windows version, the DWM might define the window size as something larger than your window (where it draws the window shadow and other effects).
Your example works OK on XP:
(There is a small problem because the titlebar is not square (unlike Windows 98/2000 that this example was designed for) so you see a issue in the top left where it is just white. I also modified the example slightly so it varies the HDC source location)
On a modern version of Windows it seems like the DWM or something is not able to properly emulate a simple window DC and parts of the shadow/border/effects area is part of the DC:
I don't know how to fix this but the example is pretty useless anyway, if you want to draw the window icon you should draw the HICON with DrawIconEx. If you want to draw custom non-client area stuff then you need to find more recent examples, not something that only supports the classic theme.

Related

GtkRevealer glitches the text view drawing

During the development of my program I came across one drawing glitch that I was unable to solve. I am using GtkRevealer to show and hide a GtkInfoBar above another box holding a scrolled window with a GtkTextView (actually GtkSourceView) a lot like it is in gedit.
The whole thing is packed in a GtkPaned.
When I hide the infobar through the revealer, a black area in the text view appears and it disappears when a redrawing of the widget must occur (for instance when I click on the text view to place the cursor)
Additionally, this glitch does not appear if I enlarge the default resolution of the window, which for compatibility reasons is 640x480.
I understand that this may be hard to reproduce, but I am unaware who encountered the same problem. He maybe knows a workaround to this issue.
Also any idea is welcome.
I will draw exactly how the glitch looks on gedit (although it doesn't happen in gedit or it does but I cannot hit the correct resolution).
I tried to force a redrawing with gtk_widget_queue_draw() but nothing happens and it won't, because it has nothing to redraw.
I will try now to place the cursor automatically. It may work, but it is not functionally adequate.
EDIT:
Surprisingly it did not work. Grabbing the focus and placing the cursor
had no effect on the glitched visual behavior. I had to even make a new line
to fix it this time.
The fact that I have to resize the window with a value more than a specific point, may mean that the glitch may be due to alignment miscaulculations, but this doesn't explain why adding new line or a text mark in the gutter that colorizes the entire line also removes the black field.
Currently this bug has been encountered in another programs with a text view as well, but hasn't been reported as a bug yet.
Perhaps this has something to do with the fact that it is hard to reproduce.
I found that hiding the gtk text view with gtk_widget_hide() and then showing it with gtk_widget_show() works. The flicker of this visual glitch is not noticeable, perhaps due to GTK+ being event-based and waiting for the function to return to process changes.

PrintScreen contents are larger than what I see

I would happily provide a screenshot of this, however the problem is the captured image, is much larger than my actual desktop.
I am completely frustrated with this as I have tried using BitBlt with the desktop hdc AND the new "Graphics" commands.
My actual desktop resolution is 1920x1080 - 1080p .
BitBlt and "Graphics" both return that my resolution is 1536x864 # 96 DPI.
A form (WinForm), Maximized, borderless, and irrelevant of scaling mode the form is set to, also shows 1536x864 # 96 DPI.
Now the image that is captured, is like it is being done from 1920x1080, but clipping the region 1536x864 as the screenshot.
If I do PrintScreen directly using Prtscn button, I get the entire image, but still it is about 1.5-2x larger than what I actually see.
What I am looking for -- is a resolution for how I can take a picture of what is on my screen in the scale/dpi/whatever is going on here that it visually looks like. I have written a screen capture program, and using a few different examples for the RubberBand form (overlay form to select a region of the screen by drawing a box), and as you can imagine, this scaling crap is causing those box captures to be offset, and the contents are zoomed.
This is very annoying -- even to explain, however I am positive that most of you are familiar with the terms I use, and also know what to expect from taking a screenshot, so my explanation above should be pretty clear as to what my problem is.
Example/Consideration
Imagine, taking a picture of a window that is 300x300, and getting the top left 150x150 of that zoomed to 300x300 completely skipping the remainder of the window. Resulting image is still 300x300, but it's not what you selected.
Now imagine, you grab a picture of your screen by the only dimensions you can get programmatically, and then put the image into a picturebox. Even though both your screen and the picturebox claim to be the same dimensions and dpi, the image in the picturebox requires scrolling even if the picturebox is maximized to fullscreen on a borderless with no borders / etc. -- again, the picture is zoomed, but how is it still reporting that it's the same size as the form XD (comparing Graphics or BitBlt dimensions with the actual form. also tried comparing picturebox contents, and still same effect)
This, is EXACTLY what the effect is that is happening. When I try to capture a region or segment of the screen. I am not sure why windows api/crl is lying about this seemingly trivial stuff, however there must be a way to accurately obtain screenshots/capture regions without this faux zoom effect -- across all resolutions.
Thank you Hans Passant for pointing me in the right direction.
To add "true" dpi scaling support to a winforms application, you can make it so by adding the following block to your manifest :
Project > Add New Item > Visual C# Items > Application Manifest File
One the file has been added, open it up and look for a line like
</asmv1:assembly>
Whatever the "asmv" number is, (in the example above it is 1), use that to format the code:
<asmv1:application>
<asmv1:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv1:windowsSettings>
</asmv1:application>
Paste the above code (changing the asmv1 to whatever version the manifest is), just above the final closing line for the ""
Also, make sure your forms are set to AutoScale to dpi (and all sub-elements).

Why is there a black lag every time a WPF window is resized?

Other questions on SE address how to speed up nested UI control resizing, but- what if there aren't any controls?
As you drag the edge of a WPF window, even a main window with no content, black bars flicker briefly during the drag. This produces a crummy feel- one that I don't want to inflict on customers:
It does get slower and heavier with a full UI on top of it as well. This doesn't even get into how ugly it looks when resizing using the top or left edges. Windows Forms- even with the heaviest UI I've built- never looks this bad right off the bat.
What can be done to make WPF window resizing performance comparable to win forms?
(I have Windows 7 x64 and a triple monitor system on an AT Radeon HD 7470.)
You could update your graphic card and try it out again but that wont change anything. The reason is pretty simple. We all get to see this sometimes based how fast/slow our computer is. Sometimes it runs smooth because we do not have many visuals to draw. The reason is no proper background color is found in graphic card at that moment in redrawing process. Your drivers are fine, and its not just because you use Wpf. Other techniques use the same mechanism behind redrawing.
The first thing WPF will do is clear out the dirty region that is going to redraw. The purpose of dirty regions is to reduce the amount of pixels sent to the output merger stage of the GPU pipeline. Here is where we see the black color. Window itself at that point has no background color or its background color is set to transparent and so to us the GPU draws the black background. Things run async in wpf which is good so.
To fix this you could set a fix color such as "White" to the Window. Then the WPF system will clean out the dirty region but fill it automatically with white color instead of black. This usually helps.
Match the window color or the color of top most layer. Dont let GPU use black and you should do fine. Btw Wpf is faster than WinForm so dont worry.
The look is crummy indeed, especially when using the top or left border.
Which exact problem your screen shot is showing depends on how long your app is taking to render as well as a couple of background related settings that you might be able to tweak to get better resize. Plus part of the ugly resize is specific to Aero.
While I can't address the specific crazy slowness of WPF redraw, I can at least give some insight on why you see black, where that is coming from, and whether you can change to a less annoying fill-in color.
It turns out there are multiple different sources of the black and the bad resize behavior from different Windows versions that combine together. Please see this Q&A which explains what is going on and provides advice for what to do (again, not specific to making WPF faster but just seeing what you can do given the speed you have):
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?

WPF performance issue when resizing the window with lots of controls

I have a WPF window that contains a fancy image with roughly 200 controls (derived from buttons), all of which use one of my 5 templates (paths, shadow effects, etc). Agreed, it is a heavy window to draw. I can live with that.
My problem comes from resizing the window. Maximize/Restore take about 1-2 seconds, but manually dragging the bottom-left corner causes the system to hang for about 5-10 seconds. In that delay, the window is black & contains partial leftovers until the final result is shown. It looks amateurish and that, I can't live with.
Remote connection : using a remote account, I found that the window resize always takes 1-2 seconds, but doesn't draw the "intermediate" stages while I'm dragging the window borders. The result is as snappy as I would expect.
My conclusion is this: It's the redraws during the resize that are bottlenecks.
The inevitable question is this : how can I prevent redrawing the window until the resize is finished?
Thanks in advance for any ideas...
#Seb: I'm beginning to think WPF is
not designed for interfaces that go
beyond 2-3 controls at a time
Visual Studio 2010 and Expression Blend should be good counterexamples. Though Visual Studio sometimes freezes the bottleneck is definitely not in the WPF rendering.
#Seb: The inevitable question is this : how
can I prevent redrawing the window
until the resize is finished?
Simply set the window's content visibility to Visibility.Collapsed before the resize/maximize and make it visible afterwards. Though I think you asked the wrong question. Here is the right one
How to make my controls measure/arrange extremely fast?
And to answer it you should take a look at your code. Maybe you intensively use dependency properties in the measuring/arrange algorithm? Or maybe you picked wrong panels (e.g. Grid is slower than Canvas)? Or maybe... I stop guessing here :).
By the way, it's always better to launch your app under profiler and prove the bottleneck rather than assuming the place where it might be. Check Eqatec Profiler it's free yet powerful enough. VS 2010 also offers nice profiling features, though it's far from being free. And you may want to check WPF Performance Suite.
Hope this helps.
Let me know how this works... I am assuming that your root visual item is stretching to horizontally and vertically to fill your window with auto height/width. Get rid of the Auto height/width. On app start up set the dimensions of the root element. There is a FrameworkElements have a size changed event. Register for this on your Application.Current.MainWindow (maybe be a typo, that was from memory). Whenever this event fires, start a timer with a small interval. If you get another resize while the timer is running, ignore it and reset the timer. Once the timer fires, you now know the new size the user desires and that they have (at least for a short period) stopped resizing the window.
Hope that helps!
From Ragepotato's answer and your comment about needing to see roughly what the interface would look like while resizing, as long as you don't have your objects dynamically re-locating themselves (like a Wrap Panel) - you could take a screenshot of the window contents and fill your frame with it.
Set it to stretch both height and width, and you'd get a (slightly fuzzy) idea of what a particular size would be. It wouldn't be live while resizing, but for those few seconds that probably wouldn't matter..

Gtk: get usable area of each monitor (excluding panels)

Using gdk_screen_get_monitor_geometry, I can get the total area in pixels and the relative position of each monitor, even when there are two or more used as a single screen.
However, I want to get the usable area (that is, excluding panels) of each monitor. The only thing I have found is _NET_WORKAREA, but that is one giant area stretching across all monitors. Depending on the resolution and arrangement, there may be panels inside this area.
How can I get the actual usable area of each monitor? Ideally, using only Gtk/Gdk, nothing X11-specific.
The following approach is a bit convoluted, but it is what I'd use. It should be robust even when there is complex interaction between the window manager and GTK+ when a window is mapped -- for example, when some of the panels are automatically hidden.
The basic idea is to create a transparent decorationless maximized window for each screen, obtain its geometry (size and position) when it gets mapped (for example, using a map-event callback), and immediately destroy them. That gets you the usable area within each screen. You can then use your existing gdk_screen_get_monitor_geometry() approach to determine how the usable area is split between monitors, if any.
In detail:
Use gdk_display_get_default() to get the default display, then gdk_display_get_n_screens() to find out how many screens it has.
Create a new window for each screen using gtk_window_new(), moving the windows to their respective screens using gtk_window_set_screen(). Undecorate the windows using gtk_window_set_decorated(,FALSE), maximuze them using gtk_window_maximize(,TRUE), and make them transparent using gtk_window_set_opacity(,0.0). Connect the map-event signal to a callback handler (using g_signal_connect()). Show the window using gtk_widget_show().
The signal handler needs to call gtk_window_get_position() and/or gtk_window_get_size() to get the position and/or size of the newly-mapped window, and then destroy the window using gtk_widget_destroy().
Note that in practice, you only need one window. I would personally use a simple loop. I suspect that due to window manager oddities/bugs, it is much more robust to create a new window for each screen, rather than just move the same window between screens. It turns out it is easier, too, as you can use a single simple callback function to obtain the usable area for each screen.
Like I said, this is quite convoluted. On the other hand, a standard application should not care about the screen sizes; it should simply do what the user or window manager asks. Because of that, I would not be surprised if there are no better facilities to find out this information. Screen size may change at any point, for example if the user rotates their display, or changes the display resolution.
in the end I ended up using xlib directly, various "tricks" like the one suggested above ended up eventually failing in the long run often with odd corner cases and never followed the KISS principle.
The solution I used is in the X-Tile code base.

Resources