411 lines
14 KiB
C
411 lines
14 KiB
C
#include "cabinet.h"
|
|
#include "cabwnd.h"
|
|
#include "rcids.h"
|
|
#include <desktray.h>
|
|
#include <trayp.h>
|
|
#include "deskconf.h"
|
|
|
|
|
|
|
|
|
|
// Support defines and functions for ConfigDesktopDlgProc and friends
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Some globals
|
|
|
|
HWND g_hdlgDesktopConfig = NULL;
|
|
BOOL g_fShouldShowConfigDesktop = FALSE;
|
|
WNDPROC g_DesktopTBProc;
|
|
|
|
|
|
|
|
|
|
// Externs and prototypes we need
|
|
|
|
#ifdef DESKBTN
|
|
extern HWND g_hwndDesktopTB;
|
|
void Tray_DesktopMenu(DWORD dwPos);
|
|
#else
|
|
#define g_hwndDesktopTB NULL
|
|
#define Tray_DesktopMenu(dwPos) 0
|
|
#endif
|
|
|
|
#define TIMER_DISMISS 1
|
|
#define TIMER_POLL 2
|
|
|
|
#define TIMEOUT_POLL_INTERVAL 50
|
|
#define TIMEOUT_DISMISS_INTERVAL 5000
|
|
|
|
#define BLEND_TRANSPARENT 0
|
|
#define BLEND_TRANSLUCENT 128
|
|
#define BLEND_OPAQUE 255
|
|
#define BLEND_INCREMENT_VAL 10
|
|
|
|
#define PrivateWS_EX_LAYERED 0x00080000
|
|
#define PrivateULW_ALPHA 0x00000002
|
|
#if (WINVER >= 0x0500)
|
|
// for files in nt5api and w5api dirs, use the definition in sdk include.
|
|
// And make sure our private define is in sync with winuser.h.
|
|
#if WS_EX_LAYERED != PrivateWS_EX_LAYERED
|
|
#error inconsistant WS_EX_LAYERED in winuser.h
|
|
#endif
|
|
#if ULW_ALPHA != PrivateULW_ALPHA
|
|
#error inconsistant ULW_ALPHA in winuser.h
|
|
#endif
|
|
|
|
#else
|
|
#define WS_EX_LAYERED PrivateWS_EX_LAYERED
|
|
#define ULW_ALPHA PrivateULW_ALPHA
|
|
#endif // (WINVER >= 0x0500)
|
|
|
|
typedef BOOL (* PFNUPDATELAYEREDWINDOW)
|
|
(HWND hwnd,
|
|
HDC hdcDst,
|
|
POINT *pptDst,
|
|
SIZE *psize,
|
|
HDC hdcSrc,
|
|
POINT *pptSrc,
|
|
COLORREF crKey,
|
|
BLENDFUNCTION *pblend,
|
|
DWORD dwFlags);
|
|
|
|
|
|
|
|
|
|
// Implementation
|
|
|
|
|
|
// Helper function used to call UpdateLayeredWindow
|
|
BOOL BlendLayeredWindow(HWND hwnd, POINT* ppt, LPPOINT pptDst, SIZE* psize, HDC hdc, BYTE bBlendConst)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
static PFNUPDATELAYEREDWINDOW pfn = NULL;
|
|
|
|
if (NULL == pfn)
|
|
{
|
|
HMODULE hmod = GetModuleHandle(TEXT("USER32"));
|
|
|
|
if (hmod)
|
|
pfn = (PFNUPDATELAYEREDWINDOW)GetProcAddress(hmod, "UpdateLayeredWindow");
|
|
}
|
|
|
|
if (pfn)
|
|
{
|
|
BLENDFUNCTION blend;
|
|
blend.BlendOp = AC_SRC_OVER;
|
|
blend.BlendFlags = 0;
|
|
blend.AlphaFormat = 0;
|
|
blend.SourceConstantAlpha = bBlendConst;
|
|
|
|
bRet = pfn(hwnd, NULL, pptDst, psize, hdc, ppt, 0, &blend,
|
|
ULW_ALPHA);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
// BOOL BlendMe(HWND hDlg, LPPOINT pptSrc, LPPOINT pptDst, LPRECT prcDlg, BYTE bCurAlpha)
|
|
|
|
// Warning: This function preserves state information between calls, thus it can only be
|
|
// used by one client - the ConfigDesktopDlg code. Do not call this function with other
|
|
// windows!
|
|
|
|
// BlendMe is used to display the window in a alpha blended manner. Unfortunately in
|
|
// order for this to work the system requires us to alpha blend from a bitmap representing
|
|
// the window we want to display. This sucks and makes our work a lot harder. Currently
|
|
// this function caches a bitmap to the window and continually uses it as the blended image
|
|
// so if the contents of the window changes they will not be reflected with this function.
|
|
// The cached bitmap is freed when BlendMe is called with a NULL hDlg parameter. BlendMe also
|
|
// makes the window "normal" again (strips the WS_EX_LAYERED) bit when the alpha value is
|
|
// requested to be at the maximum (BLEND_OPAQUE).
|
|
|
|
BOOL BlendMe(HWND hDlg, LPPOINT pptSrc, LPPOINT pptDst, LPRECT prcDlg, BYTE bCurAlpha)
|
|
{
|
|
BOOL fRetVal = FALSE;
|
|
static HBITMAP hbmp = NULL;
|
|
|
|
if (!hDlg)
|
|
{
|
|
DeleteBmp:
|
|
if (hbmp) {
|
|
DeleteObject(hbmp);
|
|
hbmp = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
if (g_bRunOnNT5)
|
|
{
|
|
HDC hdcDlg, hdcCompat;
|
|
SIZE size = {prcDlg->right - prcDlg->left, prcDlg->bottom - prcDlg->top};
|
|
HBITMAP hbmpOld;
|
|
BOOL fCreatedBmp = FALSE;
|
|
|
|
if (bCurAlpha == BLEND_OPAQUE)
|
|
{
|
|
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
|
|
InvalidateRect(hDlg, NULL, FALSE);
|
|
UpdateWindow(hDlg);
|
|
goto DeleteBmp;
|
|
}
|
|
|
|
hdcDlg = GetDC(hDlg);
|
|
hdcCompat = CreateCompatibleDC(hdcDlg);
|
|
if (hdcDlg && hdcCompat)
|
|
{
|
|
if (!hbmp)
|
|
{
|
|
hbmp = CreateCompatibleBitmap(hdcDlg, size.cx, size.cy);
|
|
fCreatedBmp = TRUE;
|
|
}
|
|
if (hbmp)
|
|
{
|
|
hbmpOld = SelectObject(hdcCompat, hbmp);
|
|
if (fCreatedBmp)
|
|
SendMessage(hDlg, WM_PRINT, (WPARAM)hdcCompat,
|
|
PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT);
|
|
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_TOOLWINDOW | WS_EX_LAYERED);
|
|
ShowWindow(hDlg, SW_SHOWNA);
|
|
BlendLayeredWindow(hDlg, pptSrc, pptDst, &size, hdcCompat, bCurAlpha);
|
|
}
|
|
SelectObject(hdcCompat, hbmpOld);
|
|
DeleteDC(hdcCompat);
|
|
ReleaseDC(hDlg, hdcDlg);
|
|
fRetVal = TRUE;
|
|
}
|
|
}
|
|
return fRetVal;
|
|
}
|
|
|
|
// Helper function used to dismiss the ConfigDesktopDlg button
|
|
void KillConfigDesktopDlg()
|
|
{
|
|
if (g_hdlgDesktopConfig)
|
|
{
|
|
BlendMe(NULL, NULL, NULL, NULL, 0);
|
|
DestroyWindow(g_hdlgDesktopConfig);
|
|
g_hdlgDesktopConfig = NULL;
|
|
}
|
|
}
|
|
|
|
// Helper function to calculate where to place the ConfigDesktopDlg button so that it is
|
|
// adjacent to the "Show Desktop" tray button.
|
|
void CalcConfigDesktopDlgPos(/* out */LPPOINT lpptDlg, /* in */LPRECT lprcDlg)
|
|
{
|
|
RECT rcButton, rcTray;
|
|
BOOL fDeskBtn = (g_hwndDesktopTB && g_ts.fShowDeskBtn);
|
|
|
|
GetWindowRect(v_hwndTray, &rcTray);
|
|
if (fDeskBtn)
|
|
{
|
|
GetWindowRect(g_hwndDesktopTB, &rcButton);
|
|
}
|
|
else
|
|
{
|
|
POINT pt;
|
|
GetCursorPos(&pt);
|
|
SetRect(&rcButton, pt.x, pt.y, pt.x, pt.y);
|
|
}
|
|
|
|
if (g_ts.uStuckPlace == STICK_BOTTOM || g_ts.uStuckPlace == STICK_TOP)
|
|
{
|
|
lpptDlg->x = rcButton.left - (fDeskBtn ? (lprcDlg->right - lprcDlg->left - (rcButton.right - rcButton.left)) : 0);
|
|
if (g_ts.uStuckPlace == STICK_BOTTOM)
|
|
lpptDlg->y = rcTray.top - (lprcDlg->bottom - lprcDlg->top);
|
|
else
|
|
lpptDlg->y = rcTray.bottom;
|
|
}
|
|
else
|
|
{
|
|
if (g_ts.uStuckPlace == STICK_LEFT)
|
|
lpptDlg->x = rcTray.right;
|
|
else
|
|
lpptDlg->x = rcTray.left - (lprcDlg->right - lprcDlg->left);
|
|
lpptDlg->y = rcButton.top;
|
|
}
|
|
}
|
|
|
|
#ifdef DESKBTN
|
|
// The purpose of this subclass is to show the ConfigDesktopDlg button when the user moves the
|
|
// mouse over the "Show Desktop" tray button and the desktop is in the raised state.
|
|
LRESULT CALLBACK DesktopTBSubclass(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (uMsg == WM_MOUSEMOVE && !g_hdlgDesktopConfig && g_fDesktopRaised && g_fShouldShowConfigDesktop)
|
|
{
|
|
RECT rc = {0, 0, 40, 20}; // Dummy rectangle
|
|
POINT pt;
|
|
HWND hwnd;
|
|
|
|
// Don't show if we find a topmost window (like our config desktop menu) on top of where the
|
|
// ConfigDesktopDlg button would go
|
|
CalcConfigDesktopDlgPos(&pt, &rc);
|
|
hwnd = WindowFromPoint(pt);
|
|
if (!(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST))
|
|
g_hdlgDesktopConfig = CreateDialog(hinstCabinet, MAKEINTRESOURCE(DLG_CONFIGDESKTOP),
|
|
HWND_DESKTOP, (DLGPROC)ConfigDesktopDlgProc);
|
|
}
|
|
|
|
return CallWindowProc(g_DesktopTBProc, hwnd, uMsg, wParam, lParam);
|
|
}
|
|
#endif
|
|
|
|
|
|
// BOOL CALLBACK ConfigDesktopDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
// This function implements the "Customize My Desktop..." button displayed adjacent to the "Show Desktop"
|
|
// tray button. If the system is capable the dialog is displayed using fade in/out via alpha blending
|
|
// so it isn't too disruptive to the content of the desktop. The button self dismisses after a timeout
|
|
// period expires and can also reshow itself after being dismissed if the mouse moves over the hot spot
|
|
// (currently the "Show Desktop" button). Clicking on the button invokes the Active Desktop Customization
|
|
// menu.
|
|
|
|
BOOL CALLBACK ConfigDesktopDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
RECT rcDlg, rcButton;
|
|
POINT pt, ptDlg;
|
|
int iAlphaTemp;
|
|
static int iCurAlpha;
|
|
static BOOL fDismissing;
|
|
|
|
switch (uMsg) {
|
|
case WM_INITDIALOG:
|
|
fDismissing = FALSE;
|
|
iCurAlpha = BLEND_TRANSPARENT + 1;
|
|
SetWindowLong(hDlg, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
|
|
GetWindowRect(hDlg, &rcDlg);
|
|
CalcConfigDesktopDlgPos(&ptDlg, &rcDlg);
|
|
SetWindowPos(hDlg, HWND_TOPMOST, ptDlg.x, ptDlg.y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE);
|
|
pt.x = pt.y = 0;
|
|
if (!BlendMe(hDlg, &pt, &ptDlg, &rcDlg, (BYTE)iCurAlpha))
|
|
ShowWindow(hDlg, SW_SHOWNA);
|
|
SetTimer(hDlg, TIMER_DISMISS, TIMEOUT_DISMISS_INTERVAL, NULL);
|
|
SetTimer(hDlg, TIMER_POLL, TIMEOUT_POLL_INTERVAL, NULL);
|
|
return FALSE;
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
DWORD dwPos;
|
|
BOOL fDeskBtn = (g_hwndDesktopTB && g_ts.fShowDeskBtn);
|
|
|
|
GetWindowRect(hDlg, &rcDlg);
|
|
dwPos = MAKELONG(((fDeskBtn && ((g_ts.uStuckPlace == STICK_TOP) || (g_ts.uStuckPlace == STICK_BOTTOM))) ? LOWORD(rcDlg.right) : LOWORD(rcDlg.left)),
|
|
(((g_ts.uStuckPlace == STICK_TOP) || ((g_ts.uStuckPlace != STICK_BOTTOM) && !fDeskBtn)) ? LOWORD(rcDlg.top) : LOWORD(rcDlg.bottom)));
|
|
KillConfigDesktopDlg();
|
|
Tray_DesktopMenu(dwPos);
|
|
}
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
switch (wParam)
|
|
{
|
|
case TIMER_POLL:
|
|
// Get positions, rectangles
|
|
GetWindowRect(hDlg, &rcDlg);
|
|
if (g_hwndDesktopTB)
|
|
GetWindowRect(g_hwndDesktopTB, &rcButton);
|
|
else
|
|
SetRectEmpty(&rcButton);
|
|
GetCursorPos(&pt);
|
|
|
|
// Defer dismissing us if the mouse is in areas we're interested in tracking
|
|
if (PtInRect(&rcDlg, pt) || PtInRect(&rcButton, pt))
|
|
{
|
|
fDismissing = FALSE;
|
|
SetTimer(hDlg, TIMER_DISMISS, TIMEOUT_DISMISS_INTERVAL, NULL);
|
|
}
|
|
|
|
// Figure out if we need to increase or decrease the alpha for the blend
|
|
if (PtInRect(&rcDlg, pt) || (!fDismissing && (iCurAlpha < BLEND_TRANSLUCENT)))
|
|
{
|
|
iAlphaTemp = iCurAlpha + BLEND_INCREMENT_VAL;
|
|
if (iAlphaTemp > BLEND_OPAQUE)
|
|
iAlphaTemp = BLEND_OPAQUE;
|
|
}
|
|
else
|
|
{
|
|
iAlphaTemp = iCurAlpha - BLEND_INCREMENT_VAL;
|
|
if (iAlphaTemp < (fDismissing ? BLEND_TRANSPARENT : BLEND_TRANSLUCENT))
|
|
iAlphaTemp = fDismissing ? BLEND_TRANSPARENT : BLEND_TRANSLUCENT;
|
|
}
|
|
|
|
// If we have calculated that the alpha has changed then update our image on the screen
|
|
if (iCurAlpha != iAlphaTemp)
|
|
{
|
|
iCurAlpha = iAlphaTemp;
|
|
GetWindowRect(hDlg, &rcDlg);
|
|
pt.x = pt.y = 0;
|
|
BlendMe(hDlg, &pt, (LPPOINT)&rcDlg, &rcDlg, (BYTE)iCurAlpha);
|
|
}
|
|
|
|
// Finally, if we are in the process of dismissing and our alpha has gone to zero then destroy us.
|
|
if (fDismissing && (iCurAlpha == BLEND_TRANSPARENT))
|
|
KillConfigDesktopDlg();
|
|
break;
|
|
|
|
case TIMER_DISMISS:
|
|
// Start the dismissal process
|
|
fDismissing = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL GetDesktopSCFPaths(LPTSTR lpszDeskQL, LPTSTR lpszSystem)
|
|
{
|
|
TCHAR szFileName[MAX_PATH];
|
|
if (SHGetSpecialFolderPath(NULL, lpszDeskQL, CSIDL_APPDATA, FALSE))
|
|
{
|
|
GetSystemDirectory(lpszSystem, MAX_PATH);
|
|
LoadString(hinstCabinet, IDS_DESKTOPQUICKLAUNCH, (LPTSTR)(lpszDeskQL + lstrlen(lpszDeskQL)), MAX_PATH - lstrlen(lpszDeskQL));
|
|
LoadString(hinstCabinet, IDS_SHOWDESKSCF, szFileName, ARRAYSIZE(szFileName));
|
|
StrCatN(lpszDeskQL, szFileName, MAX_PATH - lstrlen(lpszDeskQL));
|
|
StrCatN(lpszSystem, szFileName, MAX_PATH - lstrlen(lpszSystem));
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void ShowHideDeskBtnOnQuickLaunch(BOOL fShownOnTray)
|
|
{
|
|
if (fShownOnTray != BOOLIFY(g_ts.fShowDeskBtn))
|
|
{
|
|
TCHAR szQL[MAX_PATH], szSystem[MAX_PATH];
|
|
|
|
if (GetDesktopSCFPaths(szQL, szSystem))
|
|
{
|
|
if (fShownOnTray ? DeleteFile(szQL) : CopyFile(szSystem, szQL, TRUE))
|
|
SHChangeNotify(fShownOnTray ? SHCNE_DELETE : SHCNE_CREATE, SHCNF_PATH, szQL, NULL);
|
|
}
|
|
#if 0
|
|
DWORD dwAttribs;
|
|
TCHAR szPath[MAX_PATH];
|
|
if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_APPDATA, FALSE))
|
|
{
|
|
LoadString(hinstCabinet, IDS_DESKTOPQUICKLAUNCH, (LPTSTR)(szPath + lstrlen(szPath)), ARRAYSIZE(szPath) - lstrlen(szPath));
|
|
dwAttribs = GetFileAttributes(szPath);
|
|
if (dwAttribs != -1)
|
|
{
|
|
if (fShownOnTray)
|
|
dwAttribs |= FILE_ATTRIBUTE_HIDDEN;
|
|
else
|
|
dwAttribs &= ~FILE_ATTRIBUTE_HIDDEN;
|
|
if (SetFileAttributes(szPath, dwAttribs))
|
|
SHChangeNotify(SHCNE_ATTRIBUTES, SHCNF_PATH, szPath, NULL);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|