Windows 7 Taskbar: Thumbnail Clip and Custom Previews

March 6, 2009

one comment

Even without getting involved with the APIs, it’s clear that one of the most visually stunning features of the Windows 7 taskbar is the live multiple thumbnails shown for each window.  The new taskbar thumbnails are much smarter than their Vista counterparts, enabling you to preview a live rendering of the underlying window (a.k.a. Aero Peek) and to close the window without even switching to it.  (And of course there’s no need to mention the awesome thumbnail toolbars that we’ve seen in the previous post.)


However, the Windows 7 taskbar thumbnails are not just smarter – they are also significantly more extensible.  With a modest degree of effort, an application can customize the specific bounds of the area appearing in the thumbnail (thumbnail clip) and even render an entirely different thumbnail and live preview than the default DWM representation, enabling very interesting scenarios which improve the user’s ability to see past the thumbnail without switching to the application’s window.

For example, consider the sample Windows7.DesktopIntegration.DocumentReader application which is bundled with the managed taskbar wrappers.  It’s a really simple app, capable of rendering an RTF file in its main edit control, but here’s what its thumbnail looks like by default:


Can you read anything on that thumbnail?  I doubt that.  However, the user is clearly not interested in the entire visual rendering of this window.  He might be interested only in the few lines around the current cursor position, instead.  So why don’t we pull the managed wrapper and clip the thumbnail so that it only shows a few lines around the cursor position?

The “Toggle Clip” button does just that, and here’s a glimpse at its implementation:

private void SetClip()


    int index = rtbText.GetFirstCharIndexOfCurrentLine();

    Point point = rtbText.GetPositionFromCharIndex(index);


    Windows7Taskbar.SetThumbnailClip(Handle, new Rectangle(point, new Size(200, 119)));


In real code, you would probably not want to hardcode the 200 and 119 constants for the image width and height, but work with me here.  Look at the result:


Now THAT’S readable, isn’t it?  Just as big as the original window, only showing a clipping of its contents that is currently relevant (around the cursor position).

If this wasn’t enough, we can entirely customize what the thumbnail displays.  For example, there’s hardly any need for the window bounds and the buttons in the above image – we could squeeze more text in if we explicitly created a bitmap with some amount of text around the cursor position and showed that to the user as a thumbnail of this window.

This is somewhat more difficult that what we just did, and requires the use of the CustomWindowsManager class (from the Windows7.DesktopIntegration assembly).  By registering to the ThumbnailRequested event, the application can customize the thumbnail that is displayed by the DWM; by registering to the PeekRequested event, the application can customize the live preview that is rendered when the user hovers over the taskbar thumbnail.

The following code renders a thumbnail by explicitly drawing a few lines of text (around the cursor position) onto the drawing surface:

_windowsManager = CustomWindowsManager.CreateWindowsManager(Handle, IntPtr.Zero);

_windowsManager.PeekRequested += (o, e) =>


    e.UseWindowScreenshot = true;


_windowsManager.ThumbnailRequested += (o, e) =>


    Bitmap bmp = new Bitmap(e.Width, e.Height);

    using (Graphics g = Graphics.FromImage(bmp))


        int index = rtbText.GetFirstCharIndexOfCurrentLine();


        g.DrawString(rtbText.Text.Substring(index, Math.Min(150, rtbText.Text.Length – index)),

            new Font("Tahoma", 9),

            new SolidBrush(Color.Black),

            new RectangleF(0, 0, e.Width, e.Height));


    e.Bitmap = bmp;


Note how the PeekRequested event handler simply instructs the framework to use the window screenshot as the live peek, which is precisely what you would want if you don’t want to customize this preview aspect.

This is not all however – the application still has to override its window’s window procedure and call the DispatchMessage method of the CustomWindowsManager class to make sure the DWM notifications are dispatched appropriately:

if (_windowsManager != null)


    _windowsManager.DispatchMessage(ref m);




base.WndProc(ref m);

There’s a particularly interesting phenomenon here – grabbing a screenshot of the thumbnail preview on my system actually FAILS to include the thumbnail in the screenshot (probably because it’s custom, but I haven’t looked into this enough yet).  However, you can easily reproduce this on your Windows 7 machine by clicking the “Toggle Preview” button in the document reader sample application.

If at any time you want to disable the custom preview provided by the app, just call the DisablePreview method of the CustomWindowsManager and everything goes back to normal.

To conclude, even though there are still some glitches in the current implementation of the managed wrapper (for example, it’s unable to automatically grab a screenshot of the window if the window is minimized), it still provides a fairly easy way to customize the way your application’s thumbnail and live preview is rendered, providing exactly the look you need to achieve the best user experience.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>


one comment

  1. Ananth B.May 1, 2009 ב 10:50 PM

    Awesome wrapper. I’m hard at work writing an MP3 player that completely works off the Win7 taskbar features, with no UI (and global shortcuts).

    I’m stuck with a couple of problems, and would appreciate your help very, very much.

    1. I’m having problems showing only thumbnails (custom, which I generate) but no peek. The wrapper always calls PeekRequested. I’d like my app to work like Live Messenger, when all windows are closed and the main window minimized (to the system tray). Is this possible?
    2. Can I get a notification/event when the taskbar button is clicked?

    Thanks in advance!