In my mind, by far the coolest feature that a desktop manager can have is proper multiple (virtual) desktops (shallow, I know). So, Windows XP doesn't have this feature; ah well, there's a PowerTool that does it. Except - you can't change the desktop just by mousing off the edge, and more seriously, there doesn't appear to be any mechanism to transfer windows between desktops - which is very annoying, as things never open where you want them to.
I thought that the easiest way to do this is simply to show and hide windows in such a way as to give the impression of more than one desktop. About halfway through writing this, I discovered
SwitchDesktop, which looked quite complicated, so I didn't bother trying it that way.
The program is an MFC Dialog App.
I found out how to list all the windows on the system and show and hide them from the tbarsort article. I ask Windows for handles to every window on the system using
EnumWindows, and filter out the irrelevant ones.
bool ValidWindow(HWND hwnd)
if (!IsWindowVisible(hwnd)) return false;
if (GetWindowTextLength(hwnd) == 0) return false;
if (GetAsyncKeyState(VK_LBUTTON) &&
hwnd==GetForegroundWindow()) return false;
if(strncmp(str,"Desktop",100)==0) return false;
if(strncmp(str,"Program Manager",100)==0) return false;
BOOL CALLBACK AddToList(HWND hwnd,LPARAM ret)
Desktops can be switched by pressing the relevant button or with a keyboard shortcut, implemented with
RegisterHotKey; for example, Win+1 is registered by:
For some reason, the MFC ClassWizard doesn't know about the
WM_HOTKEY message, so it has to be added manually to the message map:
By far the hardest thing to do was to detect when the mouse touched the edge of the screen (which is when the desktops change). Eventually I found the MouseHookDlg project (although I can't currently find a reference for it), which shows how to install a global mouse hook. All I have to do is package the DLL with my app, and call the simple function
API_SetHooks to register a mouse callback, and put a handler in the message map:
having first registered this mesage by:
UWM_MOUSEMOVE = RegisterWindowMessage(UWM_SHELL_HOOK_MSG);
Finally, I wanted it to be possible to drag windows off the side of the screen and have them come with you to the new desktop. I failed to find an actual way of checking if any windows are being dragged (I suspect it can be done with another global hook); instead, if the left mouse button is down as the desktops are switched, then the foreground window is transferred, hence the line:
if (GetAsyncKeyState(VK_LBUTTON) && hwnd==GetForegroundWindow()) return false;
ValidWindow above. This works well, but occasionally leads to accidental window transfers.
The program works fine, with one or two minor bugs (not bad for only a few hours' work). Occasionally, windows get transferred when not intended, and much worse, occasionally they get permanently hidden (don't do any absolutely vital work whilst using this program, there is a small chance that this will happen and you will be unable to save). I would be glad of suggestions for bug fixes, especially for improving the dragging detection; extra features are unlikely to get added. Blatant plug: visit my site for various games written using OpenGL with MFC or GLUT.