What is VirtualDub?
VirtualDub is a video capture/processing utility for 32-bit and 64-bit Windows platforms (98/ME/NT4/2000/XP/Vista/7), licensed under the GNU General Public License (GPL). It lacks the editing power of a general-purpose editor such as Adobe Premiere, but is streamlined for fast linear operations over video. It has batch-processing capabilities for processing large numbers of files and can be extended with third-party video filters. VirtualDub is mainly geared toward processing AVI files, although it can read (not write) MPEG-1 and also handle sets of BMP images.
I basically started VirtualDub in college to do some quick capture-and-encoding that I wanted done; from there it's basically grown into a more general utility that can trim and clean up video before exporting to tape or processing with another program. I released it on the web and others found it useful, so I've been tinkering around with its code ever since. If you have the time, please download and enjoy.
§ ¶VirtualDub 1.9.8 released
VirtualDub 1.9.8 is now out, with the latest bug fixes for reported problems. Merry Christmas and Happy Holidays, everyone.
Changes in this release:
(Read more....)
§ ¶Tab control sadness
I ran into a strange problem trying to combine a tab control with a list view.
Tab controls are among the weirder of the controls in the Win32 common controls suite. A tab control lets the user select between a number of tabs, and the program then changes information displayed based on the selected tab. If you've used another UI system, you might expect the pages to be parented to the tab, but not in Win32 -- if you try to do that you quickly discover that all of your child controls break, because all of their notifications now go to the tab control. What you have to do instead is overlap the controls corresponding to the page on top of the tab control instead, with all of them parented to the dialog. This doesn't look any different to the user, but it has lots of implications for the way that the UI code is structured.
One of the annoying problems with Win32 UI is that overlapping controls in general are bad news. In theory it's not too hard of a problem to solve in a windowing system, as you just have to and dutifully paint all windows affected by any invalidation in the correct order. In practice, I've found that Windows doesn't quite get this right, and you get into many corner case redrawing problems. This is compounded by buttons, which (a) render transparent and require that the dialog itself supply the background erase, and (b) must overlap other controls when used in group box mode. Therefore, you can end up in a number of cases where a resizable dialog doesn't quite redraw correctly when resized.
In this case, the problem was a bit more severe:
![[Tabbed dialog OK] [Tabbed dialog OK]](/blog/images/tabclip1.png)
![[Tabbed dialog with artifacts] [Tabbed dialog with artifacts]](/blog/images/tabclip2.png)
Both images are of a dialog containing a tab control with a list view on top of it, created fresh in the VC++ dialog editor. The first image is how it initially displays; the second one is after changing a column width. Yuck. It was actually worse than I can show in a static image, as sometimes the entire list view would disappear.
My first thought was, oh great, the tab control is drawing over the list view. Indeed, that was the case, but according to Spy++ WS_CLIPSIBLINGS was set on the tab control, and no amount of style fiddling seemed to fix the problem. The WS_CLIPSIBLINGS flag is supposed to exclude other child windows from that window's paint, which in this case would prevent the tab control from drawing over the list view. Well, after subclassing the tab control and doing some experiments, it turns out that the documentation is both absolutely correct and still misleading. WS_CLIPSIBLINGS does indeed exclude other overlapping child windows during painting (WM_PAINT). What it does not do is exclude other windows during the background erase (WM_ERASEBKGND)! Tab controls defer to DefWindowProc() for the latter message, which dutifully does a FillRect() with the class background brush of COLOR_3DFACE... with no clip region. Owww.
I ended up "fixing" the problem by subclassing the tab control, intercepting WM_ERASEBKGND, and calling ExcludeClipRect() with the rectangle of the list view. I still can't believe that WS_CLIPSIBLINGS doesn't clip the erase operation, though, because that seems like a gaping hole in the implementation. Actually, it doesn't surprise me too much -- frankly, many parts of USER are broken as designed -- but it still bugs me because checked against the Wine source code, which appears to use the same clip region for erase and paint operations. If anyone knows of an additional condition for WM_CLIPSIBLINGS to react in this manner, I'm curious.
(Read more....)