/*++ Copyright (c) 1985 - 1999, Microsoft Corporation Module Name: menu.c Abstract: This file implements the system menu management. Author: Therese Stowell (thereses) Jan-24-1992 (swiped from Win3.1) --*/ #include "precomp.h" #pragma hdrstop VOID MyModifyMenuItem( IN PCONSOLE_INFORMATION Console, IN UINT ItemId ) /*++ This routine edits the indicated control to one word. This is used to trim the Accelerator key text off of the end of the standard menu items because we don't support the accelerators. --*/ { WCHAR ItemString[30]; int ItemLength; MENUITEMINFO mii; ItemLength = LoadString(ghInstance,ItemId,ItemString,NELEM(ItemString)); if (ItemLength == 0) { //DbgPrint("LoadString in MyModifyMenu failed %d\n",GetLastError()); return; } mii.cbSize = sizeof(mii); mii.fMask = MIIM_STRING; mii.dwTypeData = ItemString; if (ItemId == SC_CLOSE) { mii.fMask |= MIIM_BITMAP; mii.hbmpItem = HBMMENU_POPUP_CLOSE; } SetMenuItemInfo(Console->hMenu, ItemId, FALSE, &mii); } VOID InitSystemMenu( IN PCONSOLE_INFORMATION Console ) { WCHAR ItemString[30]; int ItemLength; // // load the clipboard menu. // Console->hHeirMenu = LoadMenu(ghInstance, MAKEINTRESOURCE(ID_WOMENU)); if (Console->hHeirMenu) { ItemLength = LoadString(ghInstance,cmEdit,ItemString,NELEM(ItemString)); if (ItemLength == 0) RIPMSG1(RIP_WARNING, "LoadString 1 failed 0x%x", GetLastError()); } else { RIPMSG1(RIP_WARNING, "LoadMenu 1 failed 0x%x", GetLastError()); } // // Edit the accelerators off of the standard items. // MyModifyMenuItem(Console, SC_CLOSE); // // Append the clipboard menu to system menu. // if (!AppendMenu(Console->hMenu, MF_POPUP | MF_STRING, (ULONG_PTR)Console->hHeirMenu, ItemString)) { RIPMSG1(RIP_WARNING, "AppendMenu 1 failed 0x%x", GetLastError()); } // // Add other items to system menu // ItemLength = LoadString(ghInstance, cmDefaults, ItemString, ARRAY_SIZE(ItemString)); if (ItemLength == 0) RIPMSG2(RIP_WARNING, "LoadString 0x%x failed 0x%x", cmDefaults, GetLastError()); if (ItemLength) { if (!AppendMenu(Console->hMenu, MF_STRING, cmDefaults, ItemString)) { RIPMSG2(RIP_WARNING, "AppendMenu 0x%x failed 0x%x", cmDefaults, GetLastError()); } } ItemLength = LoadString(ghInstance,cmControl,ItemString,NELEM(ItemString)); if (ItemLength == 0) RIPMSG2(RIP_WARNING, "LoadString 0x%x failed 0x%x\n", cmControl, GetLastError()); if (ItemLength) { if (!AppendMenu(Console->hMenu, MF_STRING, cmControl, ItemString)) { RIPMSG2(RIP_WARNING, "AppendMenu 0x%x failed 0x%x\n", cmControl, GetLastError()); } } } VOID InitializeMenu( IN PCONSOLE_INFORMATION Console ) /*++ this initializes the system menu when a WM_INITMENU message is read. --*/ { HMENU hMenu = Console->hMenu; HMENU hHeirMenu = Console->hHeirMenu; // // if we're in graphics mode, disable size menu // if (!(Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER)) { EnableMenuItem(hMenu,SC_SIZE,MF_GRAYED); } // // if the console is iconic, disable Mark and Scroll. // if (Console->Flags & CONSOLE_IS_ICONIC) { EnableMenuItem(hHeirMenu,cmMark,MF_GRAYED); EnableMenuItem(hHeirMenu,cmScroll,MF_GRAYED); } else { // // if the console is not iconic // if there are no scroll bars // or we're in mark mode // disable scroll // else // enable scroll // // if we're in scroll mode // disable mark // else // enable mark if ((Console->CurrentScreenBuffer->WindowMaximizedX && Console->CurrentScreenBuffer->WindowMaximizedY) || Console->Flags & CONSOLE_SELECTING) { EnableMenuItem(hHeirMenu,cmScroll,MF_GRAYED); } else { EnableMenuItem(hHeirMenu,cmScroll,MF_ENABLED); } if (Console->Flags & CONSOLE_SCROLLING) { EnableMenuItem(hHeirMenu,cmMark,MF_GRAYED); } else { EnableMenuItem(hHeirMenu,cmMark,MF_ENABLED); } } // // if we're selecting or scrolling, disable Paste. // otherwise enable it. // if (Console->Flags & (CONSOLE_SELECTING | CONSOLE_SCROLLING)) { EnableMenuItem(hHeirMenu,cmPaste,MF_GRAYED); } else { EnableMenuItem(hHeirMenu,cmPaste,MF_ENABLED); } // // if app has active selection, enable copy; else disabled // if (Console->Flags & CONSOLE_SELECTING && Console->SelectionFlags & CONSOLE_SELECTION_NOT_EMPTY) { EnableMenuItem(hHeirMenu,cmCopy,MF_ENABLED); } else { EnableMenuItem(hHeirMenu,cmCopy,MF_GRAYED); } // // disable close // if (Console->Flags & CONSOLE_DISABLE_CLOSE) EnableMenuItem(hMenu,SC_CLOSE,MF_GRAYED); else EnableMenuItem(hMenu,SC_CLOSE,MF_ENABLED); // // enable Move if not iconic // if (Console->Flags & CONSOLE_IS_ICONIC) { EnableMenuItem(hMenu,SC_MOVE,MF_GRAYED); } else { EnableMenuItem(hMenu,SC_MOVE,MF_ENABLED); } // // enable Settings if not already doing it // if (Console->hWndProperties && IsWindow(Console->hWndProperties)) { EnableMenuItem(hMenu,cmControl,MF_GRAYED); } else { EnableMenuItem(hMenu,cmControl,MF_ENABLED); Console->hWndProperties = NULL; } } VOID SetWinText( IN PCONSOLE_INFORMATION Console, IN UINT wID, IN BOOL Add ) /*++ This routine adds or removes the name to or from the beginning of the window title. The possible names are "Scroll", "Mark", "Paste", and "Copy". --*/ { WCHAR TextBuf[256]; PWCHAR TextBufPtr; int TextLength; int NameLength; WCHAR NameString[20]; NameLength = LoadString(ghInstance,wID,NameString, sizeof(NameString)/sizeof(WCHAR)); if (Add) { RtlCopyMemory(TextBuf,NameString,NameLength*sizeof(WCHAR)); TextBuf[NameLength] = ' '; TextBufPtr = TextBuf + NameLength + 1; } else { TextBufPtr = TextBuf; } TextLength = GetWindowText(Console->hWnd, TextBufPtr, sizeof(TextBuf)/sizeof(WCHAR)-NameLength-1); if (TextLength == 0) return; if (Add) { TextBufPtr = TextBuf; } else { /* * The window title might have already been reset, so make sure * the name is there before trying to remove it. */ if (wcsncmp(NameString, TextBufPtr, NameLength) != 0) return; TextBufPtr = TextBuf + NameLength + 1; } SetWindowText(Console->hWnd,TextBufPtr); } VOID PropertiesDlgShow( IN PCONSOLE_INFORMATION Console, IN BOOL fCurrent ) /*++ Displays the properties dialog and updates the window state, if necessary. --*/ { HANDLE hSection = NULL; HANDLE hClientSection = NULL; HANDLE hThread; SIZE_T ulViewSize; LARGE_INTEGER li; NTSTATUS Status; PCONSOLE_STATE_INFO pStateInfo; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PSCREEN_INFORMATION ScreenInfo; LPTHREAD_START_ROUTINE MyPropRoutine; /* * Map the shared memory block handle into the client side process's * address space. */ ProcessHandleRecord = CONTAINING_RECORD(Console->ProcessHandleList.Blink, CONSOLE_PROCESS_HANDLE, ListLink); /* * For global properties pass in hWnd for the hClientSection */ if (!fCurrent) { hClientSection = Console->hWnd; goto PropCallback; } /* * Create a shared memory block. */ li.QuadPart = sizeof(CONSOLE_STATE_INFO) + Console->OriginalTitleLength; Status = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, &li, PAGE_READWRITE, SEC_COMMIT, NULL); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "Error 0x%x creating file mapping", Status); return; } /* * Get a pointer to the shared memory block. */ pStateInfo = NULL; ulViewSize = 0; Status = NtMapViewOfSection(hSection, NtCurrentProcess(), &pStateInfo, 0, 0, NULL, &ulViewSize, ViewUnmap, 0, PAGE_READWRITE); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "Error 0x%x mapping view of file", Status); NtClose(hSection); return; } /* * Fill in the shared memory block with the current values. */ ScreenInfo = Console->CurrentScreenBuffer; pStateInfo->Length = li.LowPart; pStateInfo->ScreenBufferSize = ScreenInfo->ScreenBufferSize; pStateInfo->WindowSize.X = CONSOLE_WINDOW_SIZE_X(ScreenInfo); pStateInfo->WindowSize.Y = CONSOLE_WINDOW_SIZE_Y(ScreenInfo); pStateInfo->WindowPosX = Console->WindowRect.left; pStateInfo->WindowPosY = Console->WindowRect.top; if (ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) { pStateInfo->FontSize = SCR_FONTSIZE(ScreenInfo); pStateInfo->FontFamily = SCR_FAMILY(ScreenInfo); pStateInfo->FontWeight = SCR_FONTWEIGHT(ScreenInfo); wcscpy(pStateInfo->FaceName, SCR_FACENAME(ScreenInfo)); #if defined(FE_SB) // if TT font has external leading, the Size.Y <> SizeWant.Y // if we still pass actual Size.Y to console.cpl to query font, // it will be incorrect. Jun-26-1996 if (CONSOLE_IS_DBCS_ENABLED() && TM_IS_TT_FONT(SCR_FAMILY(ScreenInfo))) { if (SCR_FONTNUMBER(ScreenInfo) < NumberOfFonts) { pStateInfo->FontSize = FontInfo[SCR_FONTNUMBER(ScreenInfo)].SizeWant; } } #endif pStateInfo->CursorSize = ScreenInfo->BufferInfo.TextInfo.CursorSize; } pStateInfo->FullScreen = Console->FullScreenFlags & CONSOLE_FULLSCREEN; pStateInfo->QuickEdit = Console->Flags & CONSOLE_QUICK_EDIT_MODE; pStateInfo->AutoPosition = Console->Flags & CONSOLE_AUTO_POSITION; pStateInfo->InsertMode = Console->InsertMode; pStateInfo->ScreenAttributes = ScreenInfo->Attributes; pStateInfo->PopupAttributes = ScreenInfo->PopupAttributes; pStateInfo->HistoryBufferSize = Console->CommandHistorySize; pStateInfo->NumberOfHistoryBuffers = Console->MaxCommandHistories; pStateInfo->HistoryNoDup = Console->Flags & CONSOLE_HISTORY_NODUP; RtlCopyMemory(pStateInfo->ColorTable, Console->ColorTable, sizeof(Console->ColorTable)); pStateInfo->hWnd = Console->hWnd; wcscpy(pStateInfo->ConsoleTitle, Console->OriginalTitle); #if defined(FE_SB) pStateInfo->CodePage = Console->OutputCP; #endif NtUnmapViewOfSection(NtCurrentProcess(), pStateInfo); Status = NtDuplicateObject(NtCurrentProcess(), hSection, ProcessHandleRecord->ProcessHandle, &hClientSection, 0, 0, DUPLICATE_SAME_ACCESS); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "Error 0x%x mapping handle to client", Status); NtClose(hSection); return; } PropCallback: /* * Get a pointer to the client-side properties routine. */ MyPropRoutine = ProcessHandleRecord->PropRoutine; ASSERT(MyPropRoutine); /* * Call back into the client process to spawn the properties dialog. */ UnlockConsole(Console); hThread = InternalCreateCallbackThread(ProcessHandleRecord->ProcessHandle, (ULONG_PTR)MyPropRoutine, (ULONG_PTR)hClientSection); if (!hThread) { RIPMSG1(RIP_WARNING, "CreateRemoteThread failed 0x%x", GetLastError()); } LockConsole(Console); /* * Close any open handles and free allocated memory. */ if (hThread) NtClose(hThread); if (hSection) NtClose(hSection); return; } VOID PropertiesUpdate( IN PCONSOLE_INFORMATION Console, IN HANDLE hClientSection ) /*++ Updates the console state from information sent by the properties dialog box. --*/ { HANDLE hSection; SIZE_T ulViewSize; NTSTATUS Status; PCONSOLE_STATE_INFO pStateInfo; PCONSOLE_PROCESS_HANDLE ProcessHandleRecord; PSCREEN_INFORMATION ScreenInfo; ULONG FontIndex; WINDOWPLACEMENT wp; COORD NewSize; WINDOW_LIMITS WindowLimits; /* * Map the shared memory block handle into our address space. */ ProcessHandleRecord = CONTAINING_RECORD(Console->ProcessHandleList.Blink, CONSOLE_PROCESS_HANDLE, ListLink); Status = NtDuplicateObject(ProcessHandleRecord->ProcessHandle, hClientSection, NtCurrentProcess(), &hSection, 0, 0, DUPLICATE_SAME_ACCESS); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "Error 0x%x mapping client handle", Status); return; } /* * Get a pointer to the shared memory block. */ pStateInfo = NULL; ulViewSize = 0; Status = NtMapViewOfSection(hSection, NtCurrentProcess(), &pStateInfo, 0, 0, NULL, &ulViewSize, ViewUnmap, 0, PAGE_READONLY); if (!NT_SUCCESS(Status)) { RIPMSG1(RIP_WARNING, "Error %x mapping view of file", Status); NtClose(hSection); return; } /* * Verify the size of the shared memory block. */ if (ulViewSize < sizeof(CONSOLE_STATE_INFO)) { RIPMSG0(RIP_WARNING, "sizeof(hSection) < sizeof(CONSOLE_STATE_INFO)"); NtUnmapViewOfSection(NtCurrentProcess(), pStateInfo); NtClose(hSection); return; } ScreenInfo = Console->CurrentScreenBuffer; #if defined(FE_SB) if (Console->OutputCP != pStateInfo->CodePage) { UINT CodePage = Console->OutputCP; Console->OutputCP = pStateInfo->CodePage; if (CONSOLE_IS_DBCS_ENABLED()) Console->fIsDBCSOutputCP = !!IsAvailableFarEastCodePage(Console->OutputCP); else Console->fIsDBCSOutputCP = FALSE; SetConsoleCPInfo(Console,TRUE); #if defined(FE_IME) SetImeOutputCodePage(Console, ScreenInfo, CodePage); #endif // FE_IME } if (Console->CP != pStateInfo->CodePage) { UINT CodePage = Console->CP; Console->CP = pStateInfo->CodePage; if (CONSOLE_IS_DBCS_ENABLED()) Console->fIsDBCSCP = !!IsAvailableFarEastCodePage(Console->CP); else Console->fIsDBCSCP = FALSE; SetConsoleCPInfo(Console,FALSE); #if defined(FE_IME) SetImeCodePage(Console); #endif // FE_IME } #endif // FE_SB /* * Update the console state from the supplied values. */ if (!(Console->Flags & CONSOLE_VDM_REGISTERED) && (pStateInfo->ScreenBufferSize.X != ScreenInfo->ScreenBufferSize.X || pStateInfo->ScreenBufferSize.Y != ScreenInfo->ScreenBufferSize.Y)) { PCOOKED_READ_DATA CookedReadData = Console->lpCookedReadData; if (CookedReadData && CookedReadData->NumberOfVisibleChars) { DeleteCommandLine(CookedReadData, FALSE); } ResizeScreenBuffer(ScreenInfo, pStateInfo->ScreenBufferSize, TRUE); if (CookedReadData && CookedReadData->NumberOfVisibleChars) { RedrawCommandLine(CookedReadData); } } #if !defined(FE_SB) FontIndex = FindCreateFont(pStateInfo->FontFamily, pStateInfo->FaceName, pStateInfo->FontSize, pStateInfo->FontWeight); #else FontIndex = FindCreateFont(pStateInfo->FontFamily, pStateInfo->FaceName, pStateInfo->FontSize, pStateInfo->FontWeight, pStateInfo->CodePage); #endif #if defined(FE_SB) #if defined(i386) if (! (Console->FullScreenFlags & CONSOLE_FULLSCREEN)) { SetScreenBufferFont(ScreenInfo, FontIndex, pStateInfo->CodePage); } else { ChangeDispSettings(Console, Console->hWnd, 0); SetScreenBufferFont(ScreenInfo, FontIndex, pStateInfo->CodePage); ConvertToFullScreen(Console); ChangeDispSettings(Console, Console->hWnd, CDS_FULLSCREEN); } #else // i386 SetScreenBufferFont(ScreenInfo, FontIndex, pStateInfo->CodePage); #endif #else // FE_SB SetScreenBufferFont(ScreenInfo, FontIndex); #endif // FE_SB SetCursorInformation(ScreenInfo, pStateInfo->CursorSize, ScreenInfo->BufferInfo.TextInfo.CursorVisible); GetWindowLimits(ScreenInfo, &WindowLimits); NewSize.X = min(pStateInfo->WindowSize.X, WindowLimits.MaximumWindowSize.X); NewSize.Y = min(pStateInfo->WindowSize.Y, WindowLimits.MaximumWindowSize.Y); if (NewSize.X != CONSOLE_WINDOW_SIZE_X(ScreenInfo) || NewSize.Y != CONSOLE_WINDOW_SIZE_Y(ScreenInfo)) { wp.length = sizeof(wp); GetWindowPlacement(Console->hWnd, &wp); wp.rcNormalPosition.right += (NewSize.X - CONSOLE_WINDOW_SIZE_X(ScreenInfo)) * SCR_FONTSIZE(ScreenInfo).X; wp.rcNormalPosition.bottom += (NewSize.Y - CONSOLE_WINDOW_SIZE_Y(ScreenInfo)) * SCR_FONTSIZE(ScreenInfo).Y; SetWindowPlacement(Console->hWnd, &wp); } #ifdef i386 if (FullScreenInitialized && ! GetSystemMetrics(SM_REMOTESESSION)) { if (pStateInfo->FullScreen == FALSE) { if (Console->FullScreenFlags & CONSOLE_FULLSCREEN) { ConvertToWindowed(Console); #if defined(FE_SB) /* * Should not sets 0 always. * because exist CONSOLE_FULLSCREEN_HARDWARE bit by avobe * else { * ChangeDispSettings(Console, Console->hWnd, 0); * SetScreenBufferFont(ScreenInfo, FontIndex, pStateInfo->CodePage); * ConvertToFullScreen(Console); * ChangeDispSettings(Console, Console->hWnd, CDS_FULLSCREEN); * } * block. * * This block enable as follows: * 1. console window is full screen * 2. open property by ALT+SPACE * 3. changes window mode by settings. */ Console->FullScreenFlags &= ~CONSOLE_FULLSCREEN; #else ASSERT(!(Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE)); Console->FullScreenFlags = 0; #endif ChangeDispSettings(Console, Console->hWnd, 0); } } else { if (Console->FullScreenFlags == 0) { ConvertToFullScreen(Console); Console->FullScreenFlags |= CONSOLE_FULLSCREEN; ChangeDispSettings(Console, Console->hWnd, CDS_FULLSCREEN); } } } #endif if (pStateInfo->QuickEdit) { Console->Flags |= CONSOLE_QUICK_EDIT_MODE; } else { Console->Flags &= ~CONSOLE_QUICK_EDIT_MODE; } if (pStateInfo->AutoPosition) { Console->Flags |= CONSOLE_AUTO_POSITION; } else { Console->Flags &= ~CONSOLE_AUTO_POSITION; SetWindowPos(Console->hWnd, NULL, pStateInfo->WindowPosX, pStateInfo->WindowPosY, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } if (Console->InsertMode != pStateInfo->InsertMode) { SetCursorMode(ScreenInfo, FALSE); Console->InsertMode = (pStateInfo->InsertMode != FALSE); #ifdef FE_SB if (Console->lpCookedReadData) { ((PCOOKED_READ_DATA)Console->lpCookedReadData)->InsertMode = Console->InsertMode; } #endif } RtlCopyMemory(Console->ColorTable, pStateInfo->ColorTable, sizeof(Console->ColorTable)); SetScreenColors(ScreenInfo, pStateInfo->ScreenAttributes, pStateInfo->PopupAttributes, TRUE); ResizeCommandHistoryBuffers(Console, pStateInfo->HistoryBufferSize); Console->MaxCommandHistories = (SHORT)pStateInfo->NumberOfHistoryBuffers; if (pStateInfo->HistoryNoDup) { Console->Flags |= CONSOLE_HISTORY_NODUP; } else { Console->Flags &= ~CONSOLE_HISTORY_NODUP; } #if defined(FE_IME) SetUndetermineAttribute(Console) ; #endif NtUnmapViewOfSection(NtCurrentProcess(), pStateInfo); NtClose(hSection); return; }