185 lines
6.6 KiB
C++
185 lines
6.6 KiB
C++
// MinimizeToTray
|
|
//
|
|
// A couple of routines to show how to make it produce a custom caption
|
|
// animation to make it look like we are minimizing to and maximizing
|
|
// from the system tray
|
|
//
|
|
// These routines are public domain, but it would be nice if you dropped
|
|
// me a line if you use them!
|
|
//
|
|
// 1.0 29.06.2000 Initial version
|
|
// 1.1 01.07.2000 The window retains it's place in the Z-order of windows
|
|
// when minimized/hidden. This means that when restored/shown, it doen't
|
|
// always appear as the foreground window unless we call SetForegroundWindow
|
|
//
|
|
// Copyright 2000 Matthew Ellis <m.t.ellis@bigfoot.com>
|
|
#include <WINDOWS.h>
|
|
#include "MinimizeToTray.h"
|
|
|
|
// Odd. VC++6 winuser.h has IDANI_CAPTION defined (as well as IDANI_OPEN and
|
|
// IDANI_CLOSE), but the Platform SDK only has IDANI_OPEN...
|
|
|
|
// I don't know what IDANI_OPEN or IDANI_CLOSE do. Trying them in this code
|
|
// produces nothing. Perhaps they were intended for window opening and closing
|
|
// like the MAC provides...
|
|
#ifndef IDANI_OPEN
|
|
#define IDANI_OPEN 1
|
|
#endif
|
|
#ifndef IDANI_CLOSE
|
|
#define IDANI_CLOSE 2
|
|
#endif
|
|
#ifndef IDANI_CAPTION
|
|
#define IDANI_CAPTION 3
|
|
#endif
|
|
|
|
#define DEFAULT_RECT_WIDTH 150
|
|
#define DEFAULT_RECT_HEIGHT 30
|
|
|
|
// Returns the rect of where we think the system tray is. This will work for
|
|
// all current versions of the shell. If explorer isn't running, we try our
|
|
// best to work with a 3rd party shell. If we still can't find anything, we
|
|
// return a rect in the lower right hand corner of the screen
|
|
static VOID GetTrayWndRect(LPRECT lpTrayRect)
|
|
{
|
|
// First, we'll use a quick hack method. We know that the taskbar is a window
|
|
// of class Shell_TrayWnd, and the status tray is a child of this of class
|
|
// TrayNotifyWnd. This provides us a window rect to minimize to. Note, however,
|
|
// that this is not guaranteed to work on future versions of the shell. If we
|
|
// use this method, make sure we have a backup!
|
|
HWND hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
|
|
if(hShellTrayWnd)
|
|
{
|
|
HWND hTrayNotifyWnd=FindWindowEx(hShellTrayWnd,NULL,TEXT("TrayNotifyWnd"),NULL);
|
|
if(hTrayNotifyWnd)
|
|
{
|
|
GetWindowRect(hTrayNotifyWnd,lpTrayRect);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// OK, we failed to get the rect from the quick hack. Either explorer isn't
|
|
// running or it's a new version of the shell with the window class names
|
|
// changed (how dare Microsoft change these undocumented class names!) So, we
|
|
// try to find out what side of the screen the taskbar is connected to. We
|
|
// know that the system tray is either on the right or the bottom of the
|
|
// taskbar, so we can make a good guess at where to minimize to
|
|
APPBARDATA appBarData;
|
|
appBarData.cbSize=sizeof(appBarData);
|
|
if(SHAppBarMessage(ABM_GETTASKBARPOS,&appBarData))
|
|
{
|
|
// We know the edge the taskbar is connected to, so guess the rect of the
|
|
// system tray. Use various fudge factor to make it look good
|
|
switch(appBarData.uEdge)
|
|
{
|
|
case ABE_LEFT:
|
|
case ABE_RIGHT:
|
|
// We want to minimize to the bottom of the taskbar
|
|
lpTrayRect->top=appBarData.rc.bottom-100;
|
|
lpTrayRect->bottom=appBarData.rc.bottom-16;
|
|
lpTrayRect->left=appBarData.rc.left;
|
|
lpTrayRect->right=appBarData.rc.right;
|
|
break;
|
|
|
|
case ABE_TOP:
|
|
case ABE_BOTTOM:
|
|
// We want to minimize to the right of the taskbar
|
|
lpTrayRect->top=appBarData.rc.top;
|
|
lpTrayRect->bottom=appBarData.rc.bottom;
|
|
lpTrayRect->left=appBarData.rc.right-100;
|
|
lpTrayRect->right=appBarData.rc.right-16;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Blimey, we really aren't in luck. It's possible that a third party shell
|
|
// is running instead of explorer. This shell might provide support for the
|
|
// system tray, by providing a Shell_TrayWnd window (which receives the
|
|
// messages for the icons) So, look for a Shell_TrayWnd window and work out
|
|
// the rect from that. Remember that explorer's taskbar is the Shell_TrayWnd,
|
|
// and stretches either the width or the height of the screen. We can't rely
|
|
// on the 3rd party shell's Shell_TrayWnd doing the same, in fact, we can't
|
|
// rely on it being any size. The best we can do is just blindly use the
|
|
// window rect, perhaps limiting the width and height to, say 150 square.
|
|
// Note that if the 3rd party shell supports the same configuraion as
|
|
// explorer (the icons hosted in NotifyTrayWnd, which is a child window of
|
|
// Shell_TrayWnd), we would already have caught it above
|
|
hShellTrayWnd=FindWindowEx(NULL,NULL,TEXT("Shell_TrayWnd"),NULL);
|
|
if(hShellTrayWnd)
|
|
{
|
|
GetWindowRect(hShellTrayWnd,lpTrayRect);
|
|
if(lpTrayRect->right-lpTrayRect->left>DEFAULT_RECT_WIDTH)
|
|
lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
|
|
if(lpTrayRect->bottom-lpTrayRect->top>DEFAULT_RECT_HEIGHT)
|
|
lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;
|
|
|
|
return;
|
|
}
|
|
|
|
// OK. Haven't found a thing. Provide a default rect based on the current work
|
|
// area
|
|
SystemParametersInfo(SPI_GETWORKAREA,0,lpTrayRect,0);
|
|
lpTrayRect->left=lpTrayRect->right-DEFAULT_RECT_WIDTH;
|
|
lpTrayRect->top=lpTrayRect->bottom-DEFAULT_RECT_HEIGHT;
|
|
}
|
|
|
|
// Check to see if the animation has been disabled
|
|
static BOOL GetDoAnimateMinimize(VOID)
|
|
{
|
|
ANIMATIONINFO ai;
|
|
|
|
ai.cbSize=sizeof(ai);
|
|
SystemParametersInfo(SPI_GETANIMATION,sizeof(ai),&ai,0);
|
|
|
|
return ai.iMinAnimate?TRUE:FALSE;
|
|
}
|
|
|
|
VOID MinimizeWndToTray(HWND hWnd, BOOL animate)
|
|
{
|
|
if(GetDoAnimateMinimize() && animate)
|
|
{
|
|
RECT rcFrom,rcTo;
|
|
|
|
// Get the rect of the window. It is safe to use the rect of the whole
|
|
// window - DrawAnimatedRects will only draw the caption
|
|
GetWindowRect(hWnd,&rcFrom);
|
|
GetTrayWndRect(&rcTo);
|
|
|
|
// Get the system to draw our animation for us
|
|
DrawAnimatedRects(hWnd,IDANI_CAPTION,&rcFrom,&rcTo);
|
|
}
|
|
|
|
// Add the tray icon. If we add it before the call to DrawAnimatedRects,
|
|
// the taskbar gets erased, but doesn't get redrawn until DAR finishes.
|
|
// This looks untidy, so call the functions in this order
|
|
|
|
// Hide the window
|
|
ShowWindow(hWnd,SW_HIDE);
|
|
}
|
|
|
|
VOID RestoreWndFromTray(HWND hWnd, BOOL animate)
|
|
{
|
|
if(GetDoAnimateMinimize() && animate)
|
|
{
|
|
// Get the rect of the tray and the window. Note that the window rect
|
|
// is still valid even though the window is hidden
|
|
RECT rcFrom,rcTo;
|
|
GetTrayWndRect(&rcFrom);
|
|
GetWindowRect(hWnd,&rcTo);
|
|
// Get the system to draw our animation for us
|
|
DrawAnimatedRects(hWnd,IDANI_CAPTION,&rcFrom,&rcTo);
|
|
}
|
|
|
|
// Show the window, and make sure we're the foreground window
|
|
ShowWindow(hWnd,SW_SHOW);
|
|
SetActiveWindow(hWnd);
|
|
SetForegroundWindow(hWnd);
|
|
|
|
// Remove the tray icon. As described above, remove the icon after the
|
|
// call to DrawAnimatedRects, or the taskbar will not refresh itself
|
|
// properly until DAR finished
|
|
}
|
|
|
|
|
|
|