As part of my open source DeskPins clone (two separate links, one for original, one for clone on GitHub), I need to allow user to interact with desktop. I figured the easiest way would be opening a new form and paint desktop contents on top of it. Then I should be able to easily set mouse cursor and give visual cues to user about windows that is currently in focus.
A more complicated alternative would be using p/invoke to SetSystemCursor and injecting custom code in other window's WM_PAINT event queue (and potentially other WinApi related work, for example, cursor cleaning would be an issue, if my program terminates abnormally). I'd prefer not to go this way.
The code I have below is working, the only issue is screen flicker. It got better after I set DoubleBuffered = true
(instead of screen flicker it became parent form flicker), but still noticeable. So right now my form flickers every time an overlay form is opened.
Is there anything I can do to make it a smooth transition, i.e. as if a new window did not open? It's okay to have a "freeze" effect = any animation would be suspended.
public sealed partial class DesktopOverlayForm : Form
{
public DesktopOverlayForm()
{
InitializeComponent();
//make full screen
//http://stackoverflow.com/a/2176683/897326
Rectangle bounds = Screen.AllScreens
.Select(x => x.Bounds)
.Aggregate(Rectangle.Union);
this.Bounds = bounds;
//set desktop overlay image
this.BackgroundImage = MakeScreenshot();
}
/// <remarks>
/// Based on this answer on StackOverflow:
/// http://stackoverflow.com/questions/1163761/capture-screenshot-of-active-window
/// </remarks>
private static Bitmap MakeScreenshot()
{
Rectangle bounds = Screen.GetBounds(Point.Empty);
Bitmap image = new Bitmap(bounds.Width, bounds.Height);
using (Graphics g = Graphics.FromImage(image))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
return image;
}
private void DesktopOverlayForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}
}