Introduction
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.
Concept
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.
Technical Details
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;
char str[100];
GetWindowText(hwnd,str,99);
if(strncmp(str,"Desktop",100)==0) return false;
if(strncmp(str,"Program Manager",100)==0) return false;
return true;
}
BOOL CALLBACK AddToList(HWND hwnd,LPARAM ret)
{
std::vector<HWND>* vecret=(std::vector<HWND>*)ret;
if(ValidWindow(hwnd)) vecret->push_back(hwnd);
return TRUE;
}
std::vector<HWND> WindowList()
{
std::vector<HWND> windows;
EnumWindows(AddToList,LPARAM(&windows));
return windows;
}
Desktops can be switched by pressing the relevant button or with a keyboard shortcut, implemented with RegisterHotKey
; for example, Win+1 is registered by:
RegisterHotKey(GetSafeHwnd(),1,MOD_WIN,'1');
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:
ON_MESSAGE(WM_HOTKEY,OnHotKey)
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:
ON_REGISTERED_MESSAGE(UWM_MOUSEMOVE, OnHookMouseMove)
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;
in the ValidWindow
above. This works well, but occasionally leads to accidental window transfers.
Conclusion
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.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.