windows-nt/Source/XPSP1/NT/shell/osshell/progman/pmwprocs.c
2020-09-26 16:20:57 +08:00

831 lines
23 KiB
C

/*
* pmwprocs.c - window procs for program manager
*
* Copyright (c) 1991, Microsoft Corporation
*
* DESCRIPTION
*
* This file is for support of program manager under NT Windows.
* This file is/was ported from pmwprocs.c (program manager).
*
* MODIFICATION HISTORY
* Initial Version: x/x/90 Author Unknown, since he didn't feel
* like commenting the code...
*
* NT 32b Version: 1/18/91 Jeff Pack
* Intitial port to begin.
*
*
*/
#include "progman.h"
#include "dde.h"
extern BOOL bInNtSetup;
/****************************************************************************
*
* SetProgmanProperties(DWORD dwDdeId, WORD wHotKey)
*
* Called when a new instance of progman was started from a Progman group
* item. This will set the properties of the first instance of Progman,
* setting the hotkey, the window title, the icon, and minimize Progman
* if the item has Run Mimimized set.
*
* Called when Progman receives WM_EXECINSTANCE message send from 2nd progman
* instance.
*
* 08-28-92 JohanneC Created.
*
****************************************************************************/
BOOL SetProgmanProperties(DWORD dwDdeId, WORD wHotKey)
{
LPGROUPDEF lpgd;
LPITEMDEF lpid;
PGROUP pGroup = NULL;
PITEM pItem = NULL;
HWND hwndT;
BOOL Found = FALSE;
HICON hIcon;
BOOL bWasIconic = FALSE;
//
// Set Progman's hotkey.
//
SendMessage(hwndProgman, WM_SETHOTKEY, wHotKey, 0L);
//
// Find the group and the item corresponding to this information.
//
for (hwndT = GetWindow(hwndMDIClient, GW_CHILD);
hwndT;
hwndT = GetWindow(hwndT, GW_HWNDNEXT)) {
if (GetWindow(hwndT, GW_OWNER))
continue;
pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext) {
if (pItem->dwDDEId == dwDdeId) {
//
// Found a match.
//
Found = TRUE;
break;
}
}
if (Found)
break;
}
if (!Found)
return(FALSE);
//
// Set Progman Properties using the properties of its item.
//
//
// Set the new icon.
//
hIcon = DuplicateIcon(hAppInstance, GetItemIcon(pGroup->hwnd, pItem));
if (hIcon) {
HICON hiconOld = (HICON)GetClassLongPtr(hwndProgman, GCLP_HICON);
if (hiconOld)
{
DestroyIcon(hiconOld);
}
SetClassLongPtr(hwndProgman, GCLP_HICON, (LONG_PTR)hIcon);
}
if (IsIconic(hwndProgman))
bWasIconic = TRUE;
//
// Check the minimize flag.
//
lpgd = GlobalLock(pGroup->hGroup);
if (lpgd) {
lpid = ITEM(lpgd, pItem->iItem);
SetWindowText(hwndProgman, (LPTSTR) PTR(lpgd, lpid->pName));
if (GroupFlag(pGroup, pItem, (WORD)ID_MINIMIZE))
ShowWindow(hwndProgman, SW_SHOWMINNOACTIVE);
GlobalUnlock(pGroup->hGroup);
}
if (bWasIconic) {
//
// to update the icon and text.
//
ShowWindow(hwndProgman, SW_HIDE);
ShowWindow(hwndProgman, SW_SHOW);
}
return(TRUE);
}
void NEAR PASCAL RedoAllIconTitles()
// Stomps on all the title rects.
{
HWND hwndGroup;
PGROUP pGroup;
PITEM pItem;
HDC hdc;
int cch;
HFONT hFontT;
LPRECT lprcTitle;
LPTSTR lpText;
LPGROUPDEF lpgd;
LPITEMDEF lpid;
POINT pt;
for (hwndGroup=GetWindow(hwndMDIClient, GW_CHILD); hwndGroup; hwndGroup=GetWindow(hwndGroup, GW_HWNDNEXT))
{
if (GetWindow(hwndGroup, GW_OWNER))
continue;
pGroup = (PGROUP)GetWindowLongPtr(hwndGroup, GWLP_PGROUP);
lpgd = LockGroup(hwndGroup);
if (!lpgd)
{
continue;
}
for (pItem = pGroup->pItems; pItem; pItem = pItem->pNext)
{
lprcTitle = &(pItem->rcTitle);
lpid = ITEM(lpgd, pItem->iItem);
lpText = (LPTSTR) PTR(lpgd, lpid->pName);
pt.x = pItem->rcIcon.left;
pt.y = pItem->rcIcon.top;
cch = lstrlen(lpText);
hdc = GetDC(pGroup->hwnd);
hFontT = SelectObject(hdc,hFontTitle);
// compute the icon rect using DrawText
SetRectEmpty(lprcTitle);
lprcTitle->right = cxArrange - (2 * cxOffset);
DrawText(hdc, lpText, -1,
lprcTitle, bIconTitleWrap ?
DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX :
DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX | DT_SINGLELINE);
if (hFontT)
SelectObject(hdc,hFontT);
ReleaseDC(pGroup->hwnd,hdc);
lprcTitle->right += cxOffset*2;
lprcTitle->bottom+= dyBorder*2;
OffsetRect
(
lprcTitle,
(pt.x+(cxIconSpace/2)-((lprcTitle->right
-lprcTitle->left)/2)),
(pt.y+cyIconSpace-dyBorder)
);
}
UnlockGroup(hwndGroup);
}
}
/*** GetRealParent --
*
*
* HWND APIENTRY GetRealParent(HWND hWnd)
*
* ENTRY - HWND hWnd
*
* EXIT - HWND
*
* SYNOPSIS - ???
*
* WARNINGS -
* EFFECTS -
*
*/
HWND APIENTRY GetRealParent(HWND hwnd)
{
/* run up the parent chain until you find a hwnd */
/* that doesn't have WS_CHILD set*/
/* BUG BUG, these should work as is????*/
while (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD){
hwnd = (HANDLE) GetWindowLongPtr(hwnd, GWLP_HWNDPARENT);
}
return hwnd;
}
/*** AnyWriteable --
*
*
* BOOL APIENTRY AnyWriteable()
*
* ENTRY - none
*
* EXIT - BOOL xxx - TRUE if read only, FALSE if not
*
* SYNOPSIS - ???
*
* WARNINGS -
* EFFECTS -
*
*/
BOOL APIENTRY AnyWriteable()
{
PGROUP pGroup;
for (pGroup=pFirstGroup; pGroup; pGroup = pGroup->pNext)
if (!pGroup->fRO){
return TRUE;
}
return FALSE;
}
/*** ProgmanProc -- window procedure for program manager
*
*
* LONG APIENTRY ProgmanWndProc(register HWND hwnd, UINT uiMsg,
* register WPARAM wParam, LONG lParam)
*
* ENTRY - HWND hWnd
* WORD uiMsg
* WPARAM wParam
* LONG lParam
* EXIT - LONG xxx - returns info, or zero, for nothing to return
*
* SYNOPSIS - ???
*
* WARNINGS -
* EFFECTS -
*
*/
LRESULT APIENTRY ProgmanWndProc(
HWND hWnd,
UINT uiMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uiMsg) {
case WM_CREATE:
{
RECT rc;
CLIENTCREATESTRUCT ccs;
hwndProgman = hWnd;
ccs.hWindowMenu = GetSubMenu(GetMenu(hWnd), IDM_WINDOW);
ccs.idFirstChild = IDM_CHILDSTART;
GetClientRect(hwndProgman, &rc);
/*
* Don't show the MDI client until all groups have
* been created to avoid ungly painting.
*/
hwndMDIClient = CreateWindow(TEXT("MDIClient"),
NULL,
WS_CLIPCHILDREN | WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_BORDER,
rc.left - 1, rc.top - 1,
rc.right + 2, rc.bottom + 2,
hWnd, (HMENU)1, hAppInstance,
(LPTSTR)&ccs);
if (!hwndMDIClient) {
return -1;
}
break;
}
case WM_ENDSESSION:
if (wParam != 0) { // nonzero means the session is being ended.
EndSession:
/* Don't close if restricted. */
if (fNoClose)
break;
if (bSaveSettings)
WriteINIFile();
else
SaveGroupsContent(FALSE);
//
// should Flush and close all registry keys here.
//
RegFlushKey(HKEY_CURRENT_USER);
if (hkeyProgramManager) {
if (hkeyPMSettings) {
RegCloseKey(hkeyPMSettings);
}
if (hkeyPMGroups) {
RegCloseKey(hkeyPMGroups);
}
RegCloseKey(hkeyProgramManager);
}
if (hkeyProgramGroups) {
RegCloseKey(hkeyProgramGroups);
}
if (hkeyCommonGroups) {
RegFlushKey(hkeyCommonGroups);
RegCloseKey(hkeyCommonGroups);
}
/* Free the commdlg */
if (hCommdlg)
FreeLibrary(hCommdlg);
ExitProcess(0);
}
break;
case WM_CLOSE:
/*
* if wParam != 0, then this is shutdown. We don't want to logoff
* again in this case, because we're already in the middle of
* logoff. We just want to exit now.
*/
if (wParam != 0)
goto EndSession;
/* Don't close if restricted. */
if (fNoClose)
return FALSE;
if (GetKeyState(VK_SHIFT) < 0) {
WriteINIFile();
return TRUE;
}
/* Check if we've already tried to exit once... */
if (fExiting) {
SetCurrentDirectory(szOriginalDirectory);
ExitWindows(0, 0);
}
fExiting = TRUE; // Stop LockGroup from trying to do a RELOAD
// if the a lock fails due to group being
// out of date.
SetWindowLong (hwndProgman, GWL_EXITING, 1);
if (bExitWindows) {
if (lParam != (LPARAM)-1) {
//
// The user double-clicked on the system menu, use the new
// logoff dialog.
//
if (MyDialogBox(NEWLOGOFFDLG,
hwndProgman,
NewLogoffDlgProc)) {
}
}
else {
if (MyDialogBox(IDD_END_WINDOWS_SESSION,
hwndProgman,
ExitDlgProc)) {
SetCurrentDirectory(szOriginalDirectory);
ExitWindows(0, 0);
}
}
/* User clicked cancel or some app refused the ExitWindows... */
fExiting = FALSE;
SetWindowLong (hwndProgman, GWL_EXITING, 0);
break;
}
else {
if (bSaveSettings)
WriteINIFile();
else {
//
// If we are in setup, the groups and settings
// will have already been saved in the
// ExitProgman(1) dde handler.
//
if (!bInNtSetup)
SaveGroupsContent(FALSE);
}
goto CallDFP;
}
case WM_LOGOFF:
DestroyWindow(hwndProgman);
return 0;
case WM_DESTROY:
if (!WinHelp(hwndProgman, szProgmanHelp, HELP_QUIT, 0L)) {
MyMessageBox(hwndProgman, IDS_APPTITLE, IDS_WINHELPERR, NULL, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
}
/* Free font. */
DeleteObject(hFontTitle);
/* Free the commdlg junk. */
if (hCommdlg)
FreeLibrary(hCommdlg);
/*
* If user hit CTRL-ALT-DEL to logoff, restart or shutdown,
* we still need to save the settings.
*/
if (!fExiting && bSaveSettings) {
WriteINIFile();
}
else
SaveGroupsContent(FALSE);
if (hbrWorkspace) {
DeleteObject(hbrWorkspace);
hbrWorkspace = NULL;
}
/*
* Stop all translations
*/
hwndMDIClient = NULL;
hwndProgman = NULL;
PostQuitMessage(0);
break;
case WM_DDE_TERMINATE:
case WM_DDE_EXECUTE:
case WM_DDE_ACK:
case WM_DDE_REQUEST:
case WM_DDE_DATA:
case WM_DDE_ADVISE:
case WM_DDE_UNADVISE:
case WM_DDE_POKE:
case WM_DDE_INITIATE:
#ifdef DEBUG_PROGMAN_DDE
{
TCHAR szDebug[300];
wsprintf (szDebug, TEXT("%d PROGMAN: Received DDE msg 0x%x\r\n"),
GetTickCount(), uiMsg);
OutputDebugString(szDebug);
}
#endif
if (!bDisableDDE)
{
return (DDEMsgProc(hWnd, uiMsg, wParam, lParam));
}
goto CallDFP;
case WM_INITMENU:
{
BOOL bGroup;
WORD wEnable;
INT i;
PGROUP pGroup;
bGroup = (SelectionType() != TYPE_ITEM);
/*
* Disable Delete/Properties if there aren't any groups.
*/
if (!pCurrentGroup) {
wEnable = MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
} else {
wEnable = MF_BYCOMMAND | MF_ENABLED;
}
EnableMenuItem((HMENU)wParam, IDM_PROPS, wEnable);
if ((pCurrentGroup && pCurrentGroup->fRO) || dwEditLevel >= 2
|| (dwEditLevel == 1 && bGroup)) {
wEnable = MF_BYCOMMAND | MF_GRAYED | MF_DISABLED;
}
EnableMenuItem((HMENU)wParam, IDM_DELETE, wEnable);
/* Handle ArrangeItems menu... */
if (pCurrentGroup && pCurrentGroup->fRO && !bGroup)
wEnable = MF_BYCOMMAND | MF_GRAYED | MF_DISABLED;
else
wEnable = MF_BYCOMMAND | MF_ENABLED;
EnableMenuItem((HMENU)wParam, IDM_ARRANGEICONS, wEnable);
/*
* Disable Move/Copy if 1. There aren't any groups,
* 2. There aren't any items in the group,
* 3. A group is selected.
* 4. The group is read only.
* 5. Restrictions do not permit it.
* 6.There is only one group - just move
* disabled.
*/
if (!pCurrentGroup || !pCurrentGroup->pItems ||
bGroup || !AnyWriteable() || dwEditLevel >= 2) {
wEnable = MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
} else {
wEnable = MF_BYCOMMAND | MF_ENABLED;
}
EnableMenuItem((HMENU)wParam, IDM_COPY, wEnable);
if (pCurrentGroup && pCurrentGroup->fRO) {
wEnable = MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
}
EnableMenuItem((HMENU)wParam, IDM_MOVE, wEnable);
i = 0;
for (pGroup=pFirstGroup; pGroup; pGroup = pGroup->pNext) {
if (!pGroup->fRO)
i++;
}
if (i<2) {
wEnable = MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
EnableMenuItem((HMENU)wParam, IDM_MOVE, wEnable);
}
/*
* Disable Open if 1. There aren't any groups,
* 2. An empty, non-minimized group is selected.
*/
if ((!pCurrentGroup) || (!bGroup && (!pCurrentGroup->pItems)
&& (!IsIconic(pCurrentGroup->hwnd)))) {
wEnable = MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
} else {
wEnable = MF_BYCOMMAND | MF_ENABLED;
}
EnableMenuItem((HMENU)wParam, IDM_OPEN, wEnable);
/*
* Grey new if
* can't create items, or
* can't create groups and either the group is read only (can't
* create an item in it) or a group is selected
*/
if (dwEditLevel >= 2 || (dwEditLevel >= 1 &&
(bGroup || pCurrentGroup->fRO))) {
wEnable = MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
} else {
wEnable = MF_BYCOMMAND | MF_ENABLED;
}
EnableMenuItem((HMENU)wParam, IDM_NEW, wEnable);
if (fNoRun) {
EnableMenuItem((HMENU)wParam, IDM_RUN,
MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
if (fNoClose) {
EnableMenuItem((HMENU)wParam, IDM_EXIT,
MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
wParam = (WPARAM)GetSystemMenu(hWnd, FALSE);
EnableMenuItem((HMENU)wParam, (WORD)SC_CLOSE,
MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
break;
}
case WM_SIZE:
if (wParam != SIZEICONIC) {
MoveWindow(hwndMDIClient, -1, -1, LOWORD(lParam) + 2,
HIWORD(lParam) + 2, TRUE);
}
break;
case WM_SYSCOLORCHANGE:
if (hbrWorkspace) {
DeleteObject(hbrWorkspace);
}
hbrWorkspace = CreateSolidBrush(GetSysColor(COLOR_APPWORKSPACE));
//
// Fall thru
//
case WM_WININICHANGE:
{
PGROUP pGroup;
BOOL bOldIconTitleWrap;
PVOID pEnv ;
if (lstrcmpi((LPTSTR)lParam,TEXT("Environment")) ==0) {
//
// Check if the user's environment variables have changed, if so
// regenerate the environment.
//
RegenerateUserEnvironment(&pEnv, TRUE);
break;
}
bOldIconTitleWrap = bIconTitleWrap;
SystemParametersInfo(SPI_ICONHORIZONTALSPACING, 0, (PVOID)&cxArrange, FALSE);
SystemParametersInfo(SPI_ICONVERTICALSPACING, 0, (PVOID)&cyArrange, FALSE);
SystemParametersInfo(SPI_GETICONTITLEWRAP, 0, (PVOID)&bIconTitleWrap, FALSE);
// Handle title wrapping.
if (bOldIconTitleWrap != bIconTitleWrap)
RedoAllIconTitles();
for (pGroup = pFirstGroup; pGroup; pGroup = pGroup->pNext) {
NukeIconBitmap(pGroup);
if (bAutoArrange) {
ArrangeItems(pGroup->hwnd);
}
}
InvalidateRect(hWnd, NULL, TRUE);
break;
}
case WM_MENUSELECT:
if (lParam) { /*make sure menu handle isn't null*/
wMenuID = GET_WM_COMMAND_ID(wParam, lParam); /*get cmd from loword of wParam*/
hSaveMenuHandle = (HANDLE)lParam; /*Save hMenu into one variable*/
wSaveFlags = HIWORD(wParam);/*Save flags into another*/
if (wMenuID >= IDM_CHILDSTART && wMenuID < IDM_HELPINDEX) {
wMenuID = IDM_CHILDSTART;
}
bFrameSysMenu = (hSaveMenuHandle == GetSystemMenu(hwndProgman, FALSE));
if (!bFrameSysMenu && wMenuID >= 0xf000) {
//
// According to winhelp: GetSystemMenu, uMenuID >= 0xf000
// means system menu items!
//
// The group window is maximized, and group system menu
// was selected
//
wSaveFlags |= MF_SYSMENU;
}
}
break;
case WM_EXECINSTANCE:
{
/*
* Another instance of program manager has been started.
* This can not be checked using the Windows 3.1 way because
* starting apps is done asynchronously in NT, and the values
* of pExecingGroup, pExecingItem and fInExec will always be FALSE.
*
* So we use the lpReserved field in the startupInfo structure
* of the other instance to make sure is was called from progman.
* This string is of the format "dde.%d,hotkey.%d" and it is
* parsed in the other instance to extract the dde id and the hotkey.
* These are passed as wParam and lParam respectively in the
* WM_EXECINSTANCE message.
*
* - johannec 8/28/92
*/
if (wParam) {
SetProgmanProperties((DWORD)wParam, (WORD)lParam);
}
else {
/*
* The user isn't trying to run progman from within progman
* so just show them that there's a progman already running...
*/
if (IsIconic(hWnd))
ShowWindow(hWnd,SW_SHOWNORMAL);
SetForegroundWindow(hWnd);
BringWindowToTop(hWnd);
BringWindowToTop(GetLastActivePopup(hWnd));
}
break;
}
case WM_UNLOADGROUP:
UnloadGroupWindow((HWND)wParam);
break;
case WM_RELOADGROUP:
{
TCHAR szGroupKey[MAXKEYLEN+1];
WORD idGroup;
BOOL bCommonGroup;
lstrcpy(szGroupKey,((PGROUP)wParam)->lpKey);
idGroup = ((PGROUP)wParam)->wIndex;
bCommonGroup = ((PGROUP)wParam)->fCommon;
UnloadGroupWindow(((PGROUP)wParam)->hwnd);
fLowMemErrYet = FALSE;
LoadGroupWindow(szGroupKey,idGroup, bCommonGroup);
MyMessageBox(hwndProgman, IDS_GROUPFILEERR, IDS_GRPHASCHANGED,
/* szGroupKey */ NULL, MB_OK | MB_ICONEXCLAMATION);
break;
}
case WM_SYSCOMMAND:
if (fNoClose && wParam == SC_CLOSE ||
fNoClose && wParam == IDM_EXIT ||
fNoClose && wParam == IDM_SHUTDOWN ) {
break;
}
if (wParam == IDM_EXIT) {
if (fNoFileMenu)
break;
PostMessage(hwndProgman, WM_CLOSE, 0, (LPARAM)-1);
break;
}
if (wParam == IDM_SHUTDOWN) {
if (fNoFileMenu)
break;
if (bExitWindows) {
fExiting = TRUE;
SetWindowLong (hwndProgman, GWL_EXITING, 1);
/* Call the ShutdownDialog API. */
ShutdownDialog(hAppInstance, hwndProgman);
/* User clicked cancel or some app refused the ExitWindows... */
fExiting = FALSE;
SetWindowLong (hwndProgman, GWL_EXITING, 0);
}
break;
}
goto CallDFP;
case WM_COMMAND:
if (ProgmanCommandProc(hWnd, wParam, lParam)) {
break;
}
goto CallDFP;
default:
if (uiMsg == uiActivateShellWindowMessage) {
if (IsIconic(hwndProgman))
ShowWindow(hwndProgman, SW_RESTORE);
else
BringWindowToTop(hwndProgman);
} else if (uiMsg == uiConsoleWindowMessage) {
PostMessage((HWND)wParam, uiConsoleWindowMessage, (WPARAM)hWnd, 0);
} else if (uiMsg == uiSaveSettingsMessage) {
WriteINIFile();
} else if (uiMsg == uiHelpMessage) {
if (wParam == MSGF_MENU) {
/*
* Get outta menu mode if help for a menu item.
*/
if (wMenuID && hSaveMenuHandle) {
wSaveMenuIDAroundSendMessage = wMenuID; /* save*/
hSaveMenuHandleAroundSendMessage = hSaveMenuHandle;
wSaveFlagsAroundSendMessage = wSaveFlags;
SendMessage(hWnd, WM_CANCELMODE, 0, 0L);
wMenuID = wSaveMenuIDAroundSendMessage; /* restore*/
hSaveMenuHandle = hSaveMenuHandleAroundSendMessage;
wSaveFlags = wSaveFlagsAroundSendMessage;
}
if (!(wSaveFlags & MF_POPUP)) {
if (wSaveFlags & MF_SYSMENU){
dwContext = bFrameSysMenu ? IDH_SYSMENU : IDH_SYSMENUCHILD;
}
else {
dwContext = wMenuID + IDH_HELPFIRST;
}
PMHelp(hWnd);
}
}
else if (wParam == MSGF_DIALOGBOX) {
/* context range for message boxes*/
if (dwContext >= IDH_MBFIRST && dwContext <= IDH_MBLAST){
PMHelp(hWnd);
}
/* let dialog box deal with it*/
PostMessage(GetRealParent((HWND)lParam), uiHelpMessage, 0, 0L);
}
}
else{
CallDFP:
return DefFrameProc(hWnd, hwndMDIClient, uiMsg, wParam, lParam);
}
}
return 0L;
}