Files
source/Console/Console.cpp
T

4576 lines
138 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2001-2004 by Marko Bozikovic
// All rights reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Send bug reports, bug fixes, enhancements, requests, flames, etc., and
// I'll try to keep a version up to date. I can be reached as follows:
// marko.bozikovic@alterbox.net
// bozho@kset.org
/////////////////////////////////////////////////////////////////////////////
#ifdef UNICODE
#error "Unicode defined"
#endif
/////////////////////////////////////////////////////////////////////////////
// Console.cpp - console class implementation
#include "builddefines.h"
#undef CINTERFACE
//#include "stdafx.h"
//#include <atlbase.h>
#include <tchar.h>
#include <msxml.h>
#include <shellapi.h>
#include <commctrl.h>
#include <memory>
#include <io.h>
#include <fcntl.h>
#include <iostream>
#include "resource.h"
#include "FileStream.h"
//#include "ComBSTROut.h"
//#include "ComVariantOut.h"
#include "Cursors.h"
#include "Dialogs.h"
#include "Console.h"
#ifdef _DEBUG
//#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
extern HINSTANCE ghInstance;
/////////////////////////////////////////////////////////////////////////////
// Console class
/////////////////////////////////////////////////////////////////////////////
// Console window class names
const TCHAR Console::m_szConsoleClass[] = _T("Console Main Command Window");
const TCHAR Console::m_szHiddenParentClass[] = _T("Console Invisible Parent Window");
/////////////////////////////////////////////////////////////////////////////
// win console window title
const tstring Console::m_strWinConsoleTitle(_T("Console Command Window"));
/////////////////////////////////////////////////////////////////////////////
// ctor/dtor
Console::Console(LPCTSTR pszConfigFile, LPCTSTR pszShellCmdLine, LPCTSTR pszConsoleTitle, LPCTSTR pszReloadNewConfig)
: m_hWnd(NULL)
, m_bInitializing(TRUE)
, m_bReloading(FALSE)
, m_strConfigEditor(_T("notepad.exe"))
, m_strConfigEditorParams(_T(""))
, m_strShell(_T(""))
, m_strShellCmdLine(pszShellCmdLine)
, m_hwndInvisParent(NULL)
, m_hdcConsole(NULL)
, m_hdcWindow(NULL)
, m_hbmpConsole(NULL)
, m_hbmpConsoleOld(NULL)
, m_hbmpWindow(NULL)
, m_hbmpWindowOld(NULL)
, m_hBkBrush(NULL)
, m_dwMasterRepaintInt(500)
, m_dwChangeRepaintInt(50)
, m_strIconFilename(_T(""))
, m_hSmallIcon(NULL)
, m_hBigIcon(NULL)
, m_hPopupMenu(NULL)
, m_hSysMenu(NULL)
, m_hConfigFilesMenu(NULL)
, m_bPopupMenuDisabled(FALSE)
, m_strWindowTitleDefault(_tcslen(pszConsoleTitle) == 0 ? _T("console") : pszConsoleTitle)
, m_strWindowTitle(m_strWindowTitleDefault)
, m_strWindowTitleCurrent(m_strWindowTitleDefault)
, m_strFontName(_T("Courier New"))
, m_dwFontSize(10)
, m_bBold(FALSE)
, m_bItalic(FALSE)
, m_bUseFontColor(FALSE)
, m_crFontColor(RGB(0, 0, 0))
, m_hFont(NULL)
, m_hFontOld(NULL)
, m_nX(0)
, m_nY(0)
, m_nInsideBorder(0)
, m_nWindowWidth(0)
, m_nWindowHeight(0)
, m_nXBorderSize(5)
, m_nYBorderSize(5)
, m_nCaptionSize(0)
, m_nClientWidth(0)
, m_nClientHeight(0)
, m_nCharHeight(0)
, m_nCharWidth(0)
, m_dwWindowBorder(BORDER_REGULAR)
, m_bShowScrollbar(TRUE)
, m_nScrollbarStyle(FSB_REGULAR_MODE)
, m_crScrollbarColor(::GetSysColor(COLOR_3DHILIGHT))
, m_nScrollbarWidth(::GetSystemMetrics(SM_CXVSCROLL))
, m_nScrollbarButtonHeight(::GetSystemMetrics(SM_CYVSCROLL))
, m_nScrollbarThunmbHeight(::GetSystemMetrics(SM_CYVTHUMB))
, m_dwTaskbarButton(TASKBAR_BUTTON_NORMAL)
, m_bMouseDragable(TRUE)
, m_nSnapDst(10)
, m_dwDocked(DOCK_NONE)
, m_dwOriginalZOrder(Z_ORDER_REGULAR)
, m_dwCurrentZOrder(Z_ORDER_REGULAR)
, m_dwTransparency(TRANSPARENCY_NONE)
, m_byAlpha(150)
, m_byInactiveAlpha(150)
, m_crBackground(RGB(0, 0, 0))
, m_crConsoleBackground(RGB(0, 0, 0))
, m_bTintSet(FALSE)
, m_byTintOpacity(50)
, m_byTintR(0)
, m_byTintG(0)
, m_byTintB(0)
, m_bBitmapBackground(FALSE)
, m_strBackgroundFile(_T(""))
, m_hdcBackground(NULL)
, m_hbmpBackground(NULL)
, m_hbmpBackgroundOld(NULL)
, m_dwBackgroundStyle(BACKGROUND_STYLE_RESIZE)
, m_bRelativeBackground(FALSE)
, m_bExtendBackground(FALSE)
, m_nBackgroundOffsetX(0)
, m_nBackgroundOffsetY(0)
, m_bHideWindow(FALSE)
, m_bHideConsole(TRUE)
, m_dwHideConsoleTimeout(0)
, m_bStartMinimized(FALSE)
, m_dwCursorStyle(CURSOR_STYLE_CONSOLE)
, m_crCursorColor(RGB(255, 255, 255))
, m_bCursorVisible(TRUE)
, m_pCursor(NULL)
, m_hWndConsole(NULL)
, m_hStdOut(NULL)
, m_hStdOutFresh(NULL)
, m_hQuitEvent(NULL)
, m_hConsoleProcess(NULL)
, m_hMonitorThread(NULL)
, m_dwRows(50)
, m_dwColumns(80)
, m_dwBufferRows(500)
, m_bUseTextBuffer(TRUE)
, m_nTextSelection(TEXT_SELECTION_NONE)
, m_bCopyOnSelect(FALSE)
, m_bInverseShift(FALSE)
, m_hdcSelection(NULL)
, m_hbmpSelection(NULL)
, m_hbmpSelectionOld(NULL)
, m_hbrushSelection(::CreateSolidBrush(RGB(0xff, 0xff, 0xff)))
, m_pScreenBuffer(NULL)
, m_pScreenBufferNew(NULL)
, m_nTextColor(15)
, m_nTextBgColor(0)
{
#if 0
m_strConfigFile = GetFullFilename(pszConfigFile);
if (!_tcsicmp(pszReloadNewConfig, _T("yes"))) {
m_dwReloadNewConfigDefault = RELOAD_NEW_CONFIG_YES;
} else if (!_tcsicmp(pszReloadNewConfig, _T("no"))) {
m_dwReloadNewConfigDefault = RELOAD_NEW_CONFIG_NO;
} else {
m_dwReloadNewConfigDefault = RELOAD_NEW_CONFIG_PROMPT;
}
m_dwReloadNewConfig = m_dwReloadNewConfigDefault;
#endif
m_mouseCursorOffset.x = 0;
m_mouseCursorOffset.y = 0;
m_coordSelOrigin.X = 0;
m_coordSelOrigin.Y = 0;
::ZeroMemory(&m_rectSelection, sizeof(RECT));
#if 0
// get Console.exe directory
TCHAR szPathName[MAX_PATH];
::ZeroMemory(szPathName, sizeof(szPathName));
::GetModuleFileName(ghInstance, szPathName, MAX_PATH);
tstring strExeDir(szPathName);
strExeDir = strExeDir.substr(0, strExeDir.rfind(_T("\\")));
strExeDir += TCHAR('\\');
// if no config file is given, get console.xml from the startup directory
if (m_strConfigFile.length() == 0) {
m_strConfigFile = strExeDir + tstring(_T("console.xml"));
}
// get readme filename
m_strReadmeFile = strExeDir + tstring(_T("Readme.txt"));
#endif
::ZeroMemory(&m_csbiCursor, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
::ZeroMemory(&m_csbiConsole, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
SetDefaultConsoleColors();
AllocateBuffer();
// Set the stdout and stderr to this window
HANDLE myOut;
::CreatePipe( &m_hStdOut, &myOut, NULL, 0);
::SetStdHandle( STD_OUTPUT_HANDLE, myOut);
::SetStdHandle( STD_ERROR_HANDLE, myOut);
int hConHandle = _open_osfhandle((long)myOut, _O_BINARY); //_O_WTEXT);
FILE *fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
*stderr = *fp;
setvbuf( stdout, NULL, _IONBF, 0 );
// create text monitor thread
DWORD dwThreadID;
m_hMonitorThread = ::CreateThread(NULL, 0, Console::MonitorThreadStatic, this, CREATE_SUSPENDED, &dwThreadID);
::ResumeThread(m_hMonitorThread);
}
Console::~Console() {
delete[] m_pScreenBuffer;
delete[] m_pScreenBufferNew;
if (m_hSmallIcon) ::DestroyIcon(m_hSmallIcon);
if (m_hBigIcon) ::DestroyIcon(m_hBigIcon);
// ::CloseHandle(m_hConsoleProcess);
// ::CloseHandle(m_hQuitEvent);
// shutdown console process
// ::CloseHandle(m_hStdOut);
// ::CloseHandle(m_hStdOutFresh);
// if (m_hWndConsole) ::SendMessage(m_hWndConsole, WM_CLOSE, 0, 0);
// ::FreeConsole();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Public methods
/////////////////////////////////////////////////////////////////////////////
// creates and shows Console window
BOOL Console::Create(HWND notify) {
m_notifyhWnd = notify;
if (m_hWnd)
{
::ShowWindow( m_hWnd, SW_SHOW);
return TRUE;
}
if (!GetOptions()) return FALSE;
if (!RegisterWindowClasses()) return FALSE;
if (!CreateConsoleWindow()) return FALSE;
// create window DC
HDC hdcDesktop = ::GetDCEx(m_hWnd, NULL, 0);
m_hdcConsole = ::CreateCompatibleDC(hdcDesktop);
m_hdcWindow = ::CreateCompatibleDC(hdcDesktop);
::ReleaseDC(m_hWnd, hdcDesktop);
// create selection DC
m_hdcSelection = ::CreateCompatibleDC(m_hdcWindow);
if (!SetupMenus()) return FALSE;
CreateNewFont();
CreateNewBrush();
// SetWindowTransparency();
SetWindowIcons();
GetTextSize();
GetBordersDimensions();
CreateCursor();
// now we can start the monitor thread
StartShellProcess();
// set the long repaint timer
if (m_dwMasterRepaintInt) ::SetTimer(m_hWnd, TIMER_REPAINT_MASTER, m_dwMasterRepaintInt, NULL);
m_bInitializing = FALSE;
// register for files/folders drag-n-drop
::DragAcceptFiles(m_hWnd, TRUE);
RefreshScreenBuffer();
::CopyMemory(m_pScreenBuffer, m_pScreenBufferNew, sizeof(CHAR_INFO) * m_dwRows * m_dwColumns);
RepaintWindow();
::UpdateWindow(m_hWnd);
if (m_bStartMinimized) {
if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) {
m_bHideWindow = TRUE;
} else {
::ShowWindow(m_hWnd, SW_MINIMIZE);
}
} else {
::ShowWindow(m_hWnd, SW_SHOW);
}
::SetForegroundWindow(m_hWnd);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Message handlers
/////////////////////////////////////////////////////////////////////////////
void Console::OnDestroy() {
if (!m_bInitializing) {
::SetEvent(m_hQuitEvent);
::WaitForSingleObject(m_hMonitorThread, 2000);
::CloseHandle(m_hMonitorThread);
// kill timers
::KillTimer(m_hWnd, TIMER_REPAINT_CHANGE);
if (m_dwMasterRepaintInt) ::KillTimer(m_hWnd, TIMER_REPAINT_MASTER);
DestroyCursor();
// cleanup graphics objects
if (m_hFontOld) ::SelectObject(m_hdcConsole, m_hFontOld);
if (m_hFont) ::DeleteObject(m_hFont);
if (m_hBkBrush) ::DeleteObject(m_hBkBrush);
if (m_hbmpConsoleOld) ::SelectObject(m_hdcConsole, m_hbmpConsoleOld);
if (m_hbmpConsole) ::DeleteObject(m_hbmpConsole);
if (m_hbmpWindowOld) ::SelectObject(m_hdcWindow, m_hbmpWindowOld);
if (m_hbmpWindow) ::DeleteObject(m_hbmpWindow);
if (m_hbmpBackgroundOld) ::SelectObject(m_hdcBackground, m_hbmpBackgroundOld);
if (m_hbmpBackground) ::DeleteObject(m_hbmpBackground);
if (m_hdcBackground) ::DeleteDC(m_hdcBackground);
if (m_hbmpSelectionOld) ::SelectObject(m_hdcSelection, m_hbmpSelectionOld);
if (m_hbmpSelection)::DeleteObject(m_hbmpSelection);
if (m_hdcSelection) ::DeleteDC(m_hdcSelection);
if (m_hbrushSelection) ::DeleteObject(m_hbrushSelection);
::DestroyMenu(m_hConfigFilesMenu);
::DestroyMenu(m_hPopupMenu);
SetTrayIcon(NIM_DELETE);
::DeleteDC(m_hdcConsole);
::DeleteDC(m_hdcWindow);
::PostQuitMessage(0);
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnNcDestroy() {
if (!m_bInitializing) delete this;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnPaint() {
PAINTSTRUCT paintStruct;
HDC hdc = ::BeginPaint(m_hWnd, &paintStruct);
if (!m_nTextSelection) {
// if there's no selection, just blit console image
::BitBlt(
hdc,
paintStruct.rcPaint.left,
paintStruct.rcPaint.top,
paintStruct.rcPaint.right - paintStruct.rcPaint.left + 1,
paintStruct.rcPaint.bottom - paintStruct.rcPaint.top + 1,
m_hdcConsole,
paintStruct.rcPaint.left,
paintStruct.rcPaint.top,
SRCCOPY);
} else {
// there's a text selection, first compose the image in an off-screen
// buffer, and then blit it
::BitBlt(
m_hdcWindow,
paintStruct.rcPaint.left,
paintStruct.rcPaint.top,
paintStruct.rcPaint.right - paintStruct.rcPaint.left + 1,
paintStruct.rcPaint.bottom - paintStruct.rcPaint.top + 1,
m_hdcConsole,
paintStruct.rcPaint.left,
paintStruct.rcPaint.top,
SRCCOPY);
::BitBlt(
m_hdcWindow,
m_rectSelection.left,
m_rectSelection.top,
m_rectSelection.right - m_rectSelection.left,
m_rectSelection.bottom - m_rectSelection.top,
m_hdcSelection,
0,
0,
SRCINVERT);
::BitBlt(
hdc,
paintStruct.rcPaint.left,
paintStruct.rcPaint.top,
paintStruct.rcPaint.right - paintStruct.rcPaint.left + 1,
paintStruct.rcPaint.bottom - paintStruct.rcPaint.top + 1,
m_hdcWindow,
paintStruct.rcPaint.left,
paintStruct.rcPaint.top,
SRCCOPY);
}
::EndPaint(m_hWnd, &paintStruct);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnPaintTimer() {
::KillTimer(m_hWnd, TIMER_REPAINT_CHANGE);
RefreshStdOut();
RefreshScreenBuffer();
if (GetChangeRate() > 15) {
::CopyMemory(m_pScreenBuffer, m_pScreenBufferNew, sizeof(CHAR_INFO) * m_dwRows * m_dwColumns);
RepaintWindow();
} else {
RepaintWindowChanges();
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnCursorTimer() {
if (m_pCursor) {
m_pCursor->PrepareNext();
DrawCursor();
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnWindowPosChanging(WINDOWPOS* lpWndPos) {
if (!(lpWndPos->flags & SWP_NOMOVE)) {
if (m_nSnapDst >= 0) {
// we'll snap Console window to the desktop edges
RECT rectDesktop;
GetDesktopRect(rectDesktop);
m_dwDocked = DOCK_NONE;
DWORD dwLeftRight = 0;
DWORD dwTopBottom = 0;
// now, see if we're close to the edges
if (lpWndPos->x <= rectDesktop.left + m_nSnapDst) {
lpWndPos->x = rectDesktop.left;
dwLeftRight = 1;
}
if (lpWndPos->x >= rectDesktop.right - m_nWindowWidth - m_nSnapDst) {
lpWndPos->x = rectDesktop.right - m_nWindowWidth;
dwLeftRight = 2;
}
if (lpWndPos->y <= rectDesktop.top + m_nSnapDst) {
lpWndPos->y = rectDesktop.top;
dwTopBottom = 1;
}
if (lpWndPos->y >= rectDesktop.bottom - m_nWindowHeight - m_nSnapDst) {
lpWndPos->y = rectDesktop.bottom - m_nWindowHeight;
dwTopBottom = 2;
}
// now, see if the window is docked
if (dwLeftRight == 1) {
// left edge
if (dwTopBottom == 1) {
// top left
m_dwDocked = DOCK_TOP_LEFT;
} else if (dwTopBottom == 2) {
// bottom left
m_dwDocked = DOCK_BOTTOM_LEFT;
}
} else if (dwLeftRight == 2) {
// right edge
if (dwTopBottom == 1) {
// top right
m_dwDocked = DOCK_TOP_RIGHT;
} else if (dwTopBottom == 2) {
// bottom right
m_dwDocked = DOCK_BOTTOM_RIGHT;
}
}
}
m_nX = lpWndPos->x;
m_nY = lpWndPos->y;
// TRACE(_T("Win pos: %ix%i\n"), m_nX, m_nY);
// we need to repaint for relative backgrounds
// if (m_bRelativeBackground && !m_bInitializing) RepaintWindow();
}
if (m_dwCurrentZOrder == Z_ORDER_ONBOTTOM) lpWndPos->hwndInsertAfter = HWND_BOTTOM;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnActivateApp(BOOL bActivate, DWORD dwFlags) {
if (m_pCursor) {
m_pCursor->SetState(bActivate);
DrawCursor();
}
#if 0
if ((m_dwTransparency == TRANSPARENCY_ALPHA) && (m_byInactiveAlpha > 0)) {
if (bActivate) {
g_pfnSetLayeredWndAttr(m_hWnd, m_crBackground, m_byAlpha, LWA_ALPHA);
} else {
g_pfnSetLayeredWndAttr(m_hWnd, m_crBackground, m_byInactiveAlpha, LWA_ALPHA);
}
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnVScroll(WPARAM wParam) {
// TRACE(_T("VScroll\n"));
int nCurrentPos = ::GetScrollPos(m_hWnd, SB_VERT);
int nDelta = 0;
switch(LOWORD (wParam)) {
case SB_PAGEUP:
nDelta = -5;
break;
case SB_PAGEDOWN:
nDelta = 5;
break;
case SB_LINEUP:
nDelta = -1;
break;
case SB_LINEDOWN:
nDelta = 1;
break;
case SB_THUMBTRACK:
nDelta = HIWORD(wParam) - nCurrentPos;
break;
case SB_ENDSCROLL:
return;
default:
return;
}
if ((nDelta = max(-nCurrentPos, min(nDelta, (int)(m_dwBufferRows-m_dwRows) - nCurrentPos))) != 0) {
nCurrentPos += nDelta;
SMALL_RECT sr;
sr.Top = (short) nCurrentPos;
// sr.Bottom = nDelta;
sr.Left = sr.Right = 0;
m_csbiConsole.srWindow = sr;
// ::SetConsoleWindowInfo(m_hStdOutFresh, FALSE, &sr);
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = nCurrentPos;
::FlatSB_SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE);
// this seems to work/look much better than direct repainting...
::SetTimer(m_hWnd, TIMER_REPAINT_CHANGE, m_dwChangeRepaintInt, NULL);
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnInputLangChangeRequest(WPARAM wParam, LPARAM lParam) {
::PostMessage(m_hWndConsole, WM_INPUTLANGCHANGEREQUEST, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnLButtonDown(UINT uiFlags, POINTS points) {
#if 0
RECT windowRect;
::GetCursorPos(&m_mouseCursorOffset);
::GetWindowRect(m_hWnd, &windowRect);
m_mouseCursorOffset.x -= windowRect.left;
m_mouseCursorOffset.y -= windowRect.top;
if (!m_bMouseDragable ||
(m_bInverseShift == !(uiFlags & MK_SHIFT))) {
if (m_nCharWidth) {
if (m_nTextSelection == TEXT_SELECTION_SELECTED) return;
// fixed-width characters
// start copy text selection
::SetCapture(m_hWnd);
if (!m_nTextSelection) {
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = m_nClientWidth;
rect.bottom = m_nClientHeight;
::FillRect(m_hdcSelection, &rect, m_hbrushSelection);
}
m_nTextSelection = TEXT_SELECTION_SELECTING;
m_coordSelOrigin.X = min(max(points.x - m_nInsideBorder, 0) / m_nCharWidth, m_dwColumns-1);
m_coordSelOrigin.Y = min(max(points.y - m_nInsideBorder, 0) / m_nCharHeight, m_dwRows-1);
m_rectSelection.left = m_rectSelection.right = m_coordSelOrigin.X * m_nCharWidth + m_nInsideBorder;
m_rectSelection.top = m_rectSelection.bottom = m_coordSelOrigin.Y * m_nCharHeight + m_nInsideBorder;
TRACE(_T("Starting point: %ix%i\n"), m_coordSelOrigin.X, m_coordSelOrigin.Y);
}
} else {
if (m_nTextSelection) {
return;
} else if (m_bMouseDragable) {
// start to drag window
::SetCapture(m_hWnd);
}
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnLButtonUp(UINT uiFlags, POINTS points) {
if ((m_nTextSelection == TEXT_SELECTION_SELECTED) ||
// X Windows select/copy style
((m_nTextSelection == TEXT_SELECTION_SELECTING) && (m_bCopyOnSelect))) {
// if the user clicked inside the selection rectangle, copy data
if ((points.x >= m_rectSelection.left) &&
(points.x <= m_rectSelection.right) &&
(points.y >= m_rectSelection.top) &&
(points.y <= m_rectSelection.bottom)) {
CopyTextToClipboard();
}
if (m_bCopyOnSelect) ::ReleaseCapture();
ClearSelection();
} else if (m_nTextSelection == TEXT_SELECTION_SELECTING) {
if ((m_rectSelection.left == m_rectSelection.right) &&
(m_rectSelection.top == m_rectSelection.bottom)) {
m_nTextSelection = TEXT_SELECTION_NONE;
} else {
m_nTextSelection = TEXT_SELECTION_SELECTED;
}
::ReleaseCapture();
} else if (m_bMouseDragable) {
// end window drag
::ReleaseCapture();
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnLButtonDblClick(UINT uiFlags, POINTS points) {
// ToggleWindowOnTop();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnRButtonUp(UINT uiFlags, POINTS points) {
if (uiFlags & MK_SHIFT) {
PasteClipoardText();
} else {
if (m_bPopupMenuDisabled) return;
POINT point;
point.x = points.x;
point.y = points.y;
::ClientToScreen(m_hWnd, &point);
HMENU hPopup = ::GetSubMenu(m_hPopupMenu, 0);
// show popup menu
::TrackPopupMenu(hPopup, 0, point.x, point.y, 0, m_hWnd, NULL);
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnMButtonDown(UINT uiFlags, POINTS points) {
PasteClipoardText();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnMouseMove(UINT uiFlags, POINTS points) {
#if 0
RECT windowRect;
int deltaX, deltaY;
POINT point;
if (uiFlags & MK_LBUTTON) {
::GetWindowRect(m_hWnd, &windowRect);
point.x = points.x;
point.y = points.y;
::ClientToScreen(m_hWnd, &point);
deltaX = point.x - windowRect.left - m_mouseCursorOffset.x;
deltaY = point.y - windowRect.top - m_mouseCursorOffset.y;
if (deltaX | deltaY) {
// TRACE(_T("m_nTextSelection: %i, Delta X: %i Delta Y: %i\n"), m_nTextSelection, deltaX, deltaY);
if (m_nTextSelection) {
if ((!m_bMouseDragable) || (m_bInverseShift == !(uiFlags & MK_SHIFT))) {
// some text has been selected, just return
if (m_nTextSelection == TEXT_SELECTION_SELECTED) return;
// selecting text for copy/paste
COORD coordSel;
::InvalidateRect(m_hWnd, &m_rectSelection, FALSE);
coordSel.X = min(max(points.x - m_nInsideBorder, 0) / m_nCharWidth, m_dwColumns-1);
coordSel.Y = min(max(points.y - m_nInsideBorder, 0) / m_nCharHeight, m_dwRows-1);
// TRACE(_T("End point: %ix%i\n"), coordSel.X, coordSel.Y);
if (coordSel.X >= m_coordSelOrigin.X) {
m_rectSelection.left = m_coordSelOrigin.X * m_nCharWidth + m_nInsideBorder;
m_rectSelection.right = (coordSel.X + 1) * m_nCharWidth + m_nInsideBorder;
} else {
m_rectSelection.left = coordSel.X * m_nCharWidth + m_nInsideBorder;
m_rectSelection.right = (m_coordSelOrigin.X + 1) * m_nCharWidth + m_nInsideBorder;
}
if (coordSel.Y >= m_coordSelOrigin.Y) {
m_rectSelection.top = m_coordSelOrigin.Y * m_nCharHeight + m_nInsideBorder;
m_rectSelection.bottom = (coordSel.Y + 1) * m_nCharHeight + m_nInsideBorder;
} else {
m_rectSelection.top = coordSel.Y * m_nCharHeight + m_nInsideBorder;
m_rectSelection.bottom = (m_coordSelOrigin.Y + 1) * m_nCharHeight + m_nInsideBorder;
}
// TRACE(_T("Selection rect: %i,%i x %i,%i\n"), m_rectSelection.left, m_rectSelection.top, m_rectSelection.right, m_rectSelection.bottom);
::InvalidateRect(m_hWnd, &m_rectSelection, FALSE);
}
} else if (m_bMouseDragable) {
// moving the window
HWND hwndZ;
switch (m_dwCurrentZOrder) {
case Z_ORDER_REGULAR : hwndZ = HWND_NOTOPMOST; break;
case Z_ORDER_ONTOP : hwndZ = HWND_TOPMOST; break;
case Z_ORDER_ONBOTTOM : hwndZ = HWND_BOTTOM; break;
}
::SetWindowPos(
m_hWnd,
hwndZ,
windowRect.left + deltaX,
windowRect.top + deltaY,
0,
0,
SWP_NOSIZE);
::PostMessage(m_hWnd, WM_PAINT, 0, 0);
}
}
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnChar(WORD myChar) {
wchar_t text[16];
if (myChar == 8)
{
int l = Input.length();
if (l > 0)
{
wchar_t last = Input[ l - 1];
if (last == '\n')
{
return;
}
text[0] = 8;
text[1] = L' ';
text[2] = 8;
text[3] = 0;
Input.resize( l - 1);
}
else
{
return;
}
}
else if (myChar == '\r')
{
text[0] = '\n';
text[1] = '\r';
text[2] = 0;
Input += '\n';
SendTextToConsole( text);
SendMessage( m_notifyhWnd, WM_INPUTREADY, 0, (LPARAM) &Input);
return;
}
else
{
text[0] = myChar;
text[1] = 0;
Input += text;
}
SendTextToConsole( text);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnSetCursor(WORD wHitTest, WORD wMouseMessage) {
if (wHitTest == HTBORDER) {
if (wMouseMessage == WM_LBUTTONDOWN) {
if (m_bMouseDragable) {
// start to drag window
RECT windowRect;
::GetCursorPos(&m_mouseCursorOffset);
::GetWindowRect(m_hWnd, &windowRect);
m_mouseCursorOffset.x -= windowRect.left;
m_mouseCursorOffset.y -= windowRect.top;
::SetCapture(m_hWnd);
}
} else if (wMouseMessage == WM_LBUTTONUP) {
if (m_bMouseDragable) {
// end window drag
::ReleaseCapture();
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnInitMenuPopup(HMENU hMenu, UINT uiPos, BOOL bSysMenu) {
if ((hMenu != ::GetSubMenu(m_hPopupMenu, 0)) && (hMenu != m_hSysMenu)) return;
// update configuration files submenu
UpdateConfigFilesSubmenu();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnDropFiles(HDROP hDrop) {
UINT uiFilesCount = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
tstring strFilenames(_T(""));
// concatenate all filenames
for (UINT i = 0; i < uiFilesCount; ++i) {
TCHAR szFilename[MAX_PATH];
::ZeroMemory(szFilename, sizeof(szFilename));
::DragQueryFile(hDrop, i, szFilename, MAX_PATH);
tstring strFilename(szFilename);
// if there are spaces in the filename, put quotes around it
if (strFilename.find(_T(" ")) != tstring::npos) strFilename = tstring(_T("\"")) + strFilename + tstring(_T("\""));
if (i > 0) strFilenames += _T(" ");
strFilenames += strFilename;
}
::DragFinish(hDrop);
// This function takes text, not file names
// SendTextToConsole(strFilenames.c_str());
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (HIWORD(wParam) == 0) {
// popup menu
return HandleMenuCommand(LOWORD(wParam));
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::OnSysCommand(WPARAM wParam, LPARAM lParam) {
return HandleMenuCommand(wParam);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::OnTrayNotify(WPARAM wParam, LPARAM lParam) {
switch (lParam) {
case WM_RBUTTONUP: {
if (m_bPopupMenuDisabled) return;
POINT posCursor;
::GetCursorPos(&posCursor);
// show popup menu
::SetForegroundWindow(m_hWnd);
::TrackPopupMenu(::GetSubMenu(m_hPopupMenu, 0), 0, posCursor.x, posCursor.y, 0, m_hWnd, NULL);
::PostMessage(m_hWnd, WM_NULL, 0, 0);
return;
}
case WM_LBUTTONDOWN:
m_bHideWindow = false;
ShowHideWindow();
::SetForegroundWindow(m_hWnd);
return;
case WM_LBUTTONDBLCLK:
m_bHideWindow = !m_bHideWindow;
ShowHideWindow();
::SetForegroundWindow(m_hWnd);
return;
default : return;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#if 0
void Console::OnWallpaperChanged(const TCHAR* pszFilename) {
if (m_dwTransparency == TRANSPARENCY_FAKE) {
SetWindowTransparency();
CreateBackgroundBitmap();
RepaintWindow();
}
}
#endif
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::GetOptions() {
#if 0
class XmlException {
public: XmlException(BOOL bRet) : m_bRet(bRet){};
BOOL m_bRet;
};
BOOL bRet = FALSE;
IStream* pFileStream = NULL;
IXMLDocument* pConfigDoc = NULL;
IPersistStreamInit* pPersistStream = NULL;
IXMLElement* pRootElement = NULL;
IXMLElementCollection* pColl = NULL;
IXMLElement* pFontElement = NULL;
IXMLElement* pPositionElement = NULL;
IXMLElement* pAppearanceElement = NULL;
IXMLElement* pScrollbarElement = NULL;
IXMLElement* pBackgroundElement = NULL;
IXMLElement* pCursorElement = NULL;
IXMLElement* pBehaviorElement = NULL;
try {
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
USES_CONVERSION;
// open file stream
if (!SUCCEEDED(CreateFileStream(
m_strConfigFile.c_str(),
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL,
&pFileStream))) {
throw XmlException(FALSE);
}
// create XML document instance
if (!SUCCEEDED(::CoCreateInstance(
CLSID_XMLDocument,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLDocument,
(void**)&pConfigDoc))) {
throw XmlException(FALSE);
}
// load the configuration file
pConfigDoc->QueryInterface(IID_IPersistStreamInit, (void **)&pPersistStream);
if (!SUCCEEDED(pPersistStream->Load(pFileStream))) throw XmlException(FALSE);
// see if we're dealing with the skin
if (!SUCCEEDED(pConfigDoc->get_root(&pRootElement))) throw XmlException(FALSE);
CComVariantOut varAttValue;
CComBSTROut bstr;
CComBSTROut strText;
tstring strTempText(_T(""));
// root element must be CONSOLE
pRootElement->get_tagName(bstr.Out());
bstr.ToUpper();
if (!(bstr == CComBSTR(_T("CONSOLE")))) throw XmlException(FALSE);
pRootElement->getAttribute(CComBSTR(_T("title")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) {
m_strWindowTitle = OLE2T(varAttValue.bstrVal);
m_strWindowTitleCurrent = m_strWindowTitle;
}
pRootElement->getAttribute(CComBSTR(_T("refresh")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_dwMasterRepaintInt = _ttol(OLE2T(varAttValue.bstrVal));
pRootElement->getAttribute(CComBSTR(_T("change_refresh")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_dwChangeRepaintInt = _ttol(OLE2T(varAttValue.bstrVal));
if ((int)m_dwChangeRepaintInt < 5) m_dwChangeRepaintInt = 5;
pRootElement->getAttribute(CComBSTR(_T("shell")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_strShell = OLE2T(varAttValue.bstrVal);
pRootElement->getAttribute(CComBSTR(_T("editor")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_strConfigEditor = OLE2T(varAttValue.bstrVal);
pRootElement->getAttribute(CComBSTR(_T("editor_params")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_strConfigEditorParams = OLE2T(varAttValue.bstrVal);
pRootElement->get_children(&pColl);
if (!pColl) throw XmlException(TRUE);
// get font settings
IXMLElementCollection* pFontColl = NULL;
if (!SUCCEEDED(pColl->item(CComVariant(_T("font")), CComVariant(0), (IDispatch**)&pFontElement))) throw XmlException(FALSE);
if (pFontElement) {
if (!SUCCEEDED(pFontElement->get_children(&pFontColl))) throw XmlException(FALSE);
if (pFontColl) {
IXMLElement* pFontSubelement = NULL;
if (!SUCCEEDED(pFontColl->item(CComVariant(_T("size")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE);
if (pFontSubelement) {
pFontSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_dwFontSize = _ttoi(OLE2T(strText));
}
SAFERELEASE(pFontSubelement);
if (!SUCCEEDED(pFontColl->item(CComVariant(_T("italic")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE);
if (pFontSubelement) {
pFontSubelement->get_text(strText.Out());
m_bItalic = !_tcsicmp(OLE2T(strText), _T("true"));
}
SAFERELEASE(pFontSubelement);
if (!SUCCEEDED(pFontColl->item(CComVariant(_T("bold")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE);
if (pFontSubelement) {
pFontSubelement->get_text(strText.Out());
m_bBold = !_tcsicmp(OLE2T(strText), _T("true"));
}
SAFERELEASE(pFontSubelement);
if (!SUCCEEDED(pFontColl->item(CComVariant(_T("name")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE);
if (pFontSubelement) {
pFontSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_strFontName = OLE2T(strText);
}
SAFERELEASE(pFontSubelement);
if (!SUCCEEDED(pFontColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE);
if (pFontSubelement) {
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
varAttValue.Clear();
pFontSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal));
varAttValue.Clear();
pFontSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal));
varAttValue.Clear();
pFontSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal));
m_bUseFontColor = TRUE;
m_crFontColor = RGB(r, g, b);
}
SAFERELEASE(pFontSubelement);
// get font color mapping
if (!SUCCEEDED(pFontColl->item(CComVariant(_T("colors")), CComVariant(0), (IDispatch**)&pFontSubelement))) throw XmlException(FALSE);
if (pFontSubelement) {
IXMLElementCollection* pColorsColl = NULL;
if (!SUCCEEDED(pFontSubelement->get_children(&pColorsColl))) throw XmlException(FALSE);
if (pColorsColl) {
for (int i = 0; i < 16; ++i) {
IXMLElement* pColorSubelement = NULL;
TCHAR szColorName[32];
_sntprintf(szColorName, sizeof(szColorName)/sizeof(TCHAR), _T("color_%02i"), i);
if (!SUCCEEDED(pColorsColl->item(CComVariant(szColorName), CComVariant(0), (IDispatch**)&pColorSubelement))) throw XmlException(FALSE);
if (pColorSubelement) {
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
varAttValue.Clear();
pColorSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal));
varAttValue.Clear();
pColorSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal));
varAttValue.Clear();
pColorSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal));
Console::m_arrConsoleColors[i] = RGB(r, g, b);
}
SAFERELEASE(pColorSubelement);
}
}
SAFERELEASE(pColorsColl);
}
SAFERELEASE(pFontSubelement);
}
SAFERELEASE(pFontColl);
}
// get position settings
IXMLElementCollection* pPositionColl = NULL;
if (!SUCCEEDED(pColl->item(CComVariant(_T("position")), CComVariant(0), (IDispatch**)&pPositionElement))) throw XmlException(FALSE);
if (pPositionElement) {
if (!SUCCEEDED(pPositionElement->get_children(&pPositionColl))) throw XmlException(FALSE);
if (pPositionColl) {
IXMLElement* pPositionSubelement = NULL;
if (!m_bReloading) {
if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("x")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE);
if (pPositionSubelement) {
pPositionSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_nX = _ttoi(OLE2T(strText));
}
SAFERELEASE(pPositionSubelement);
if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("y")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE);
if (pPositionSubelement) {
pPositionSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_nY = _ttoi(OLE2T(strText));
}
SAFERELEASE(pPositionSubelement);
}
if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("docked")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE);
if (pPositionSubelement) {
pPositionSubelement->get_text(strText.Out());
strTempText = OLE2T(strText);
if (!_tcsicmp(strTempText.c_str(), _T("top left"))) {
m_dwDocked = DOCK_TOP_LEFT;
} else if (!_tcsicmp(strTempText.c_str(), _T("top right"))) {
m_dwDocked = DOCK_TOP_RIGHT;
} else if (!_tcsicmp(strTempText.c_str(), _T("bottom right"))) {
m_dwDocked = DOCK_BOTTOM_RIGHT;
} else if (!_tcsicmp(strTempText.c_str(), _T("bottom left"))) {
m_dwDocked = DOCK_BOTTOM_LEFT;
} else {
m_dwDocked = DOCK_NONE;
}
}
SAFERELEASE(pPositionSubelement);
if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("snap_distance")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE);
if (pPositionSubelement) {
pPositionSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_nSnapDst = _ttoi(OLE2T(strText));
}
SAFERELEASE(pPositionSubelement);
if (!SUCCEEDED(pPositionColl->item(CComVariant(_T("z_order")), CComVariant(0), (IDispatch**)&pPositionSubelement))) throw XmlException(FALSE);
if (pPositionSubelement) {
pPositionSubelement->get_text(strText.Out());
strTempText = OLE2T(strText);
if (!_tcsicmp(strTempText.c_str(), _T("regular"))) {
m_dwCurrentZOrder = Z_ORDER_REGULAR;
m_dwOriginalZOrder = Z_ORDER_REGULAR;
} else if (!_tcsicmp(strTempText.c_str(), _T("on top"))) {
m_dwCurrentZOrder = Z_ORDER_ONTOP;
m_dwOriginalZOrder = Z_ORDER_ONTOP;
} else if (!_tcsicmp(strTempText.c_str(), _T("on bottom"))) {
m_dwCurrentZOrder = Z_ORDER_ONBOTTOM;
m_dwOriginalZOrder = Z_ORDER_ONBOTTOM;
} else {
m_dwCurrentZOrder = Z_ORDER_REGULAR;
m_dwOriginalZOrder = Z_ORDER_REGULAR;
}
}
SAFERELEASE(pPositionSubelement);
}
SAFERELEASE(pPositionColl);
}
// get appearance settings
IXMLElementCollection* pAppearanceColl = NULL;
if (!SUCCEEDED(pColl->item(CComVariant(_T("appearance")), CComVariant(0), (IDispatch**)&pAppearanceElement))) throw XmlException(FALSE);
if (pAppearanceElement) {
if (!SUCCEEDED(pAppearanceElement->get_children(&pAppearanceColl))) throw XmlException(FALSE);
if (pAppearanceColl) {
IXMLElement* pAppearanaceSubelement = NULL;
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("hide_console")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("true"))) {
m_bHideConsole = TRUE;
} else {
m_bHideConsole = FALSE;
}
}
SAFERELEASE(pAppearanaceSubelement);
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("hide_console_timeout")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_dwHideConsoleTimeout = _ttoi(OLE2T(strText));
}
SAFERELEASE(pAppearanaceSubelement);
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("start_minimized")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("true"))) {
m_bStartMinimized = TRUE;
} else {
m_bStartMinimized = FALSE;
}
}
SAFERELEASE(pAppearanaceSubelement);
IXMLElementCollection* pScrollbarColl = NULL;
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("scrollbar")), CComVariant(0), (IDispatch**)&pScrollbarElement))) throw XmlException(FALSE);
if (pScrollbarElement) {
if (!SUCCEEDED(pScrollbarElement->get_children(&pScrollbarColl))) throw XmlException(FALSE);
if (pScrollbarColl) {
IXMLElement* pScrollbarSubelement = NULL;
if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE);
if (pScrollbarSubelement) {
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
pScrollbarSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal));
pScrollbarSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal));
pScrollbarSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal));
m_crScrollbarColor = RGB(r, g, b);
}
SAFERELEASE(pScrollbarSubelement);
if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("style")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE);
if (pScrollbarSubelement) {
pScrollbarSubelement->get_text(strText.Out());
strTempText = OLE2T(strText);
if (!_tcsicmp(strTempText.c_str(), _T("regular"))) {
m_nScrollbarStyle = FSB_REGULAR_MODE;
} else if (!_tcsicmp(strTempText.c_str(), _T("flat"))) {
m_nScrollbarStyle = FSB_FLAT_MODE;
} else if (!_tcsicmp(strTempText.c_str(), _T("encarta"))) {
m_nScrollbarStyle = FSB_ENCARTA_MODE;
}
}
SAFERELEASE(pScrollbarSubelement);
if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("width")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE);
if (pScrollbarSubelement) {
pScrollbarSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_nScrollbarWidth = _ttoi(OLE2T(strText));
}
SAFERELEASE(pScrollbarSubelement);
if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("button_height")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE);
if (pScrollbarSubelement) {
pScrollbarSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_nScrollbarButtonHeight = _ttoi(OLE2T(strText));
}
SAFERELEASE(pScrollbarSubelement);
if (!SUCCEEDED(pScrollbarColl->item(CComVariant(_T("thumb_height")), CComVariant(0), (IDispatch**)&pScrollbarSubelement))) throw XmlException(FALSE);
if (pScrollbarSubelement) {
pScrollbarSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_nScrollbarThunmbHeight = _ttoi(OLE2T(strText));
}
SAFERELEASE(pScrollbarSubelement);
}
SAFERELEASE(pScrollbarColl);
}
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("border")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("true")) || !_tcsicmp(OLE2T(strText), _T("regular"))) {
m_dwWindowBorder = BORDER_REGULAR;
} else if (!_tcsicmp(OLE2T(strText), _T("thin"))) {
m_dwWindowBorder = BORDER_THIN;
} else {
m_dwWindowBorder = BORDER_NONE;
}
}
SAFERELEASE(pAppearanaceSubelement);
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("inside_border")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_nInsideBorder = _ttoi(OLE2T(strText));
}
SAFERELEASE(pAppearanaceSubelement);
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("taskbar_button")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("hide"))) {
m_dwTaskbarButton = TASKBAR_BUTTON_HIDE;
} else if (!_tcsicmp(OLE2T(strText), _T("tray"))) {
m_dwTaskbarButton = TASKBAR_BUTTON_TRAY;
} else {
m_dwTaskbarButton = TASKBAR_BUTTON_NORMAL;
}
}
SAFERELEASE(pAppearanaceSubelement);
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("size")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->getAttribute(CComBSTR(_T("rows")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) {
if (_tcsicmp(OLE2T(varAttValue.bstrVal), _T("max")) == 0) {
m_dwRows = 0;
} else {
m_dwRows = _ttoi(OLE2T(varAttValue.bstrVal));
}
}
pAppearanaceSubelement->getAttribute(CComBSTR(_T("columns")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) {
if (_tcsicmp(OLE2T(varAttValue.bstrVal), _T("max")) == 0) {
m_dwColumns = 0;
} else {
m_dwColumns = _ttoi(OLE2T(varAttValue.bstrVal));
}
}
pAppearanaceSubelement->getAttribute(CComBSTR(_T("buffer_rows")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) {
m_dwBufferRows = _ttoi(OLE2T(varAttValue.bstrVal));
m_bUseTextBuffer = TRUE;
} else {
m_dwBufferRows = m_dwRows;
}
}
SAFERELEASE(pAppearanaceSubelement);
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("transparency")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->getAttribute(CComBSTR(_T("alpha")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_byAlpha = (BYTE)_ttoi(OLE2T(varAttValue.bstrVal));
pAppearanaceSubelement->getAttribute(CComBSTR(_T("inactive_alpha")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_byInactiveAlpha = (BYTE)_ttoi(OLE2T(varAttValue.bstrVal));
pAppearanaceSubelement->get_text(strText.Out());
strTempText = OLE2T(strText);
if (!_tcsicmp(strTempText.c_str(), _T("none"))) {
m_dwTransparency = TRANSPARENCY_NONE;
} else if (!_tcsicmp(strTempText.c_str(), _T("alpha"))) {
m_dwTransparency = TRANSPARENCY_ALPHA;
} else if (!_tcsicmp(strTempText.c_str(), _T("color key"))) {
m_dwTransparency = TRANSPARENCY_COLORKEY;
} else if (!_tcsicmp(strTempText.c_str(), _T("fake"))) {
m_dwTransparency = TRANSPARENCY_FAKE;
}
}
SAFERELEASE(pAppearanaceSubelement);
// get background settings
IXMLElementCollection* pBackgroundColl = NULL;
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("background")), CComVariant(0), (IDispatch**)&pBackgroundElement))) throw XmlException(FALSE);
if (pBackgroundElement) {
if (!SUCCEEDED(pBackgroundElement->get_children(&pBackgroundColl))) throw XmlException(FALSE);
if (pBackgroundColl) {
IXMLElement* pBackgroundSubelement = NULL;
if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE);
if (pBackgroundSubelement) {
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
pBackgroundSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal));
pBackgroundSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal));
pBackgroundSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal));
m_crBackground = RGB(r, g, b);
}
SAFERELEASE(pBackgroundSubelement);
if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("console_color")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE);
if (pBackgroundSubelement) {
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
pBackgroundSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal));
pBackgroundSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal));
pBackgroundSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal));
m_crConsoleBackground = RGB(r, g, b);
}
SAFERELEASE(pBackgroundSubelement);
if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("tint")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE);
if (pBackgroundSubelement) {
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
pBackgroundSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_byTintR = _ttoi(OLE2T(varAttValue.bstrVal));
pBackgroundSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_byTintG = _ttoi(OLE2T(varAttValue.bstrVal));
pBackgroundSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_byTintB = _ttoi(OLE2T(varAttValue.bstrVal));
pBackgroundSubelement->getAttribute(CComBSTR(_T("opacity")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) m_byTintOpacity = _ttoi(OLE2T(varAttValue.bstrVal));
if (m_byTintOpacity > 100) m_byTintOpacity = 50;
m_bTintSet = TRUE;
}
SAFERELEASE(pBackgroundSubelement);
if (!SUCCEEDED(pBackgroundColl->item(CComVariant(_T("image")), CComVariant(0), (IDispatch**)&pBackgroundSubelement))) throw XmlException(FALSE);
if (pBackgroundSubelement) {
pBackgroundSubelement->getAttribute(CComBSTR(_T("style")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) {
if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("resize"))) {
m_dwBackgroundStyle = BACKGROUND_STYLE_RESIZE;
} else if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("center"))) {
m_dwBackgroundStyle = BACKGROUND_STYLE_CENTER;
} else if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("tile"))) {
m_dwBackgroundStyle = BACKGROUND_STYLE_TILE;
}
}
pBackgroundSubelement->getAttribute(CComBSTR(_T("relative")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) {
if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("true"))) {
m_bRelativeBackground = TRUE;
} else {
m_bRelativeBackground = FALSE;
}
}
pBackgroundSubelement->getAttribute(CComBSTR(_T("extend")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) {
if (!_tcsicmp(OLE2T(varAttValue.bstrVal), _T("true"))) {
m_bExtendBackground = TRUE;
} else {
m_bExtendBackground = FALSE;
}
}
pBackgroundSubelement->get_text(strText.Out());
m_strBackgroundFile = OLE2T(strText);
m_bBitmapBackground = TRUE;
}
SAFERELEASE(pBackgroundSubelement);
}
SAFERELEASE(pBackgroundColl);
}
IXMLElementCollection* pCursorColl = NULL;
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("cursor")), CComVariant(0), (IDispatch**)&pCursorElement))) throw XmlException(FALSE);
if (pCursorElement) {
if (!SUCCEEDED(pCursorElement->get_children(&pCursorColl))) throw XmlException(FALSE);
if (pCursorColl) {
IXMLElement* pCursorSubelement = NULL;
if (!SUCCEEDED(pCursorColl->item(CComVariant(_T("color")), CComVariant(0), (IDispatch**)&pCursorSubelement))) throw XmlException(FALSE);
if (pCursorSubelement) {
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
pCursorSubelement->getAttribute(CComBSTR(_T("r")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) r = _ttoi(OLE2T(varAttValue.bstrVal));
pCursorSubelement->getAttribute(CComBSTR(_T("g")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) g = _ttoi(OLE2T(varAttValue.bstrVal));
pCursorSubelement->getAttribute(CComBSTR(_T("b")), varAttValue.Out());
if (varAttValue.vt == VT_BSTR) b = _ttoi(OLE2T(varAttValue.bstrVal));
m_crCursorColor = RGB(r, g, b);
}
SAFERELEASE(pCursorSubelement);
if (!SUCCEEDED(pCursorColl->item(CComVariant(_T("style")), CComVariant(0), (IDispatch**)&pCursorSubelement))) throw XmlException(FALSE);
if (pCursorSubelement) {
pCursorSubelement->get_text(strText.Out());
strTempText = OLE2T(strText);
if (!_tcsicmp(strTempText.c_str(), _T("none"))) {
m_dwCursorStyle = CURSOR_STYLE_NONE;
} else if (!_tcsicmp(strTempText.c_str(), _T("XTerm"))) {
m_dwCursorStyle = CURSOR_STYLE_XTERM;
} else if (!_tcsicmp(strTempText.c_str(), _T("block"))) {
m_dwCursorStyle = CURSOR_STYLE_BLOCK;
} else if (!_tcsicmp(strTempText.c_str(), _T("noblink block"))) {
m_dwCursorStyle = CURSOR_STYLE_NBBLOCK;
} else if (!_tcsicmp(strTempText.c_str(), _T("pulse block"))) {
m_dwCursorStyle = CURSOR_STYLE_PULSEBLOCK;
} else if (!_tcsicmp(strTempText.c_str(), _T("bar"))) {
m_dwCursorStyle = CURSOR_STYLE_BAR;
} else if (!_tcsicmp(strTempText.c_str(), _T("console"))) {
m_dwCursorStyle = CURSOR_STYLE_CONSOLE;
} else if (!_tcsicmp(strTempText.c_str(), _T("noblink line"))) {
m_dwCursorStyle = CURSOR_STYLE_NBHLINE;
} else if (!_tcsicmp(strTempText.c_str(), _T("horizontal line"))) {
m_dwCursorStyle = CURSOR_STYLE_HLINE;
} else if (!_tcsicmp(strTempText.c_str(), _T("vertical line"))) {
m_dwCursorStyle = CURSOR_STYLE_VLINE;
} else if (!_tcsicmp(strTempText.c_str(), _T("rect"))) {
m_dwCursorStyle = CURSOR_STYLE_RECT;
} else if (!_tcsicmp(strTempText.c_str(), _T("noblink rect"))) {
m_dwCursorStyle = CURSOR_STYLE_NBRECT;
} else if (!_tcsicmp(strTempText.c_str(), _T("pulse rect"))) {
m_dwCursorStyle = CURSOR_STYLE_PULSERECT;
} else if (!_tcsicmp(strTempText.c_str(), _T("fading block"))) {
m_dwCursorStyle = CURSOR_STYLE_FADEBLOCK;
}
}
SAFERELEASE(pCursorSubelement);
}
SAFERELEASE(pCursorColl);
}
if (!SUCCEEDED(pAppearanceColl->item(CComVariant(_T("icon")), CComVariant(0), (IDispatch**)&pAppearanaceSubelement))) throw XmlException(FALSE);
if (pAppearanaceSubelement) {
pAppearanaceSubelement->get_text(strText.Out());
if (strText.Length() > 0) m_strIconFilename = OLE2T(strText);
}
SAFERELEASE(pAppearanaceSubelement);
}
SAFERELEASE(pAppearanceColl);
}
// get behaviour settings
IXMLElementCollection* pBehaviorColl = NULL;
if (!SUCCEEDED(pColl->item(CComVariant(_T("behaviour")), CComVariant(0), (IDispatch**)&pBehaviorElement))) {
if (!SUCCEEDED(pColl->item(CComVariant(_T("behavior")), CComVariant(0), (IDispatch**)&pBehaviorElement))) throw XmlException(FALSE);
}
if (pBehaviorElement) {
if (!SUCCEEDED(pBehaviorElement->get_children(&pBehaviorColl))) throw XmlException(FALSE);
if (pBehaviorColl) {
IXMLElement* pBehaviourSubelement = NULL;
if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("mouse_drag")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE);
if (pBehaviourSubelement) {
pBehaviourSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("true"))) {
m_bMouseDragable = TRUE;
} else {
m_bMouseDragable = FALSE;
}
}
SAFERELEASE(pBehaviourSubelement);
if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("copy_on_select")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE);
if (pBehaviourSubelement) {
pBehaviourSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("true"))) {
m_bCopyOnSelect = TRUE;
} else {
m_bCopyOnSelect = FALSE;
}
}
SAFERELEASE(pBehaviourSubelement);
if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("inverse_shift")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE);
if (pBehaviourSubelement) {
pBehaviourSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("true"))) {
m_bInverseShift = TRUE;
} else {
m_bInverseShift = FALSE;
}
}
SAFERELEASE(pBehaviourSubelement);
if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("reload_new_config")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE);
if (pBehaviourSubelement) {
pBehaviourSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("yes"))) {
m_dwReloadNewConfig = RELOAD_NEW_CONFIG_YES;
} else if (!_tcsicmp(OLE2T(strText), _T("no"))) {
m_dwReloadNewConfig = RELOAD_NEW_CONFIG_NO;
} else {
m_dwReloadNewConfig = RELOAD_NEW_CONFIG_PROMPT;
}
}
SAFERELEASE(pBehaviourSubelement);
if (!SUCCEEDED(pBehaviorColl->item(CComVariant(_T("disable_menu")), CComVariant(0), (IDispatch**)&pBehaviourSubelement))) throw XmlException(FALSE);
if (pBehaviourSubelement) {
pBehaviourSubelement->get_text(strText.Out());
if (!_tcsicmp(OLE2T(strText), _T("true"))) {
m_bPopupMenuDisabled = TRUE;
} else {
m_bPopupMenuDisabled = FALSE;
}
}
SAFERELEASE(pBehaviourSubelement);
}
SAFERELEASE(pBehaviorColl);
}
bRet = TRUE;
} catch (const XmlException& e) {
bRet = e.m_bRet;
}
SAFERELEASE(pBehaviorElement);
SAFERELEASE(pCursorElement);
SAFERELEASE(pBackgroundElement);
SAFERELEASE(pScrollbarElement);
SAFERELEASE(pAppearanceElement);
SAFERELEASE(pPositionElement);
SAFERELEASE(pFontElement);
SAFERELEASE(pColl);
SAFERELEASE(pRootElement);
SAFERELEASE(pPersistStream);
SAFERELEASE(pConfigDoc);
SAFERELEASE(pFileStream);
::CoUninitialize();
return bRet;
#endif
return 1;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::RegisterWindowClasses() {
WNDCLASSEX wcx;
// register the Console window class
::ZeroMemory(&wcx, sizeof(WNDCLASSEX));
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
wcx.lpfnWndProc = Console::WindowProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = sizeof(void*);
wcx.hInstance = ghInstance;
wcx.hIcon = ::LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_ICON2));
wcx.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = ::CreateSolidBrush(RGB(0, 0, 0));
wcx.lpszMenuName = NULL;
wcx.lpszClassName = Console::m_szConsoleClass;
wcx.hIconSm = NULL;
if ((::RegisterClassEx(&wcx) == 0) && (::GetLastError() != ERROR_CLASS_ALREADY_EXISTS)) return FALSE;
// register the hidden parent window class
::ZeroMemory(&wcx, sizeof(WNDCLASSEX));
wcx.cbSize = sizeof(wcx);
wcx.style = 0;
wcx.lpfnWndProc = ::DefWindowProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = ghInstance;
wcx.hIcon = NULL;
wcx.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = NULL;
wcx.lpszMenuName = NULL;
wcx.lpszClassName = Console::m_szHiddenParentClass;
wcx.hIconSm = NULL;
if ((::RegisterClassEx(&wcx) == 0) && (::GetLastError() != ERROR_CLASS_ALREADY_EXISTS)) return FALSE;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::SetupMenus() {
MENUITEMINFO mii;
// setup popup menu
if ((m_hPopupMenu = ::LoadMenu(ghInstance, MAKEINTRESOURCE(IDR_POPUP_MENU))) == NULL) return FALSE;
if ((m_hConfigFilesMenu = ::CreateMenu()) == NULL) return FALSE;
// add stuff to the system menu
TCHAR* arrMenuItems[] = {_T("&Copy"), _T("&Paste")};
DWORD arrMenuTypes[] = {MFT_STRING, MFT_STRING};
DWORD arrMenuIDs[] = { ID_COPY, ID_PASTE};
m_hSysMenu = ::GetSystemMenu(m_hWnd, FALSE);
for (int i = 0; i < sizeof(arrMenuIDs)/sizeof(arrMenuIDs[0]); ++i) {
::ZeroMemory(&mii, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.fType = arrMenuTypes[i];
if (mii.fType == MFT_STRING) {
mii.wID = arrMenuIDs[i];
mii.dwTypeData = arrMenuItems[i];
mii.cch = _tcslen(arrMenuItems[i]);
} else {
mii.wID = 0;
}
::InsertMenuItem(m_hSysMenu, SC_CLOSE, FALSE, &mii);
}
// set config files menu as a submenu of "Select configuration file" item
// in the popup and system menus
::ZeroMemory(&mii, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU;
mii.hSubMenu = m_hConfigFilesMenu;
// ::SetMenuItemInfo(m_hPopupMenu, ID_SEL_CONFIG_FILE, FALSE, &mii);
// ::SetMenuItemInfo(m_hSysMenu, ID_SEL_CONFIG_FILE, FALSE, &mii);
// load the initial list (so the list can be used by external programs)
UpdateConfigFilesSubmenu();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::CreateConsoleWindow() {
// create the window
DWORD dwWindowStyle = WS_VSCROLL;
if (m_dwTaskbarButton == TASKBAR_BUTTON_NORMAL) dwWindowStyle |= WS_MINIMIZEBOX;
switch (m_dwWindowBorder) {
case BORDER_NONE :
dwWindowStyle |= WS_POPUPWINDOW & ~WS_BORDER;
break;
case BORDER_REGULAR :
dwWindowStyle |= WS_CAPTION|WS_SYSMENU;
break;
case BORDER_THIN :
dwWindowStyle |= WS_POPUPWINDOW;
break;
default: dwWindowStyle |= WS_POPUPWINDOW & ~WS_BORDER;
}
// If the taskbar style is set to hide or tray, we create an invisible window
// to parent the main window to. This hides the taskbar button while allowing
// us to use the normal title bar.
if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) {
if ((m_hwndInvisParent = ::CreateWindowEx(
WS_EX_TOOLWINDOW,
Console::m_szHiddenParentClass,
_T(""),
WS_POPUP,
0,
0,
0,
0,
NULL,
NULL,
ghInstance,
NULL)) == NULL) {
return FALSE;
}
// don't let the user minimize it if there's no way to restore it
if (m_dwTaskbarButton == TASKBAR_BUTTON_HIDE) dwWindowStyle &= ~WS_MINIMIZEBOX;
}
if ((m_hWnd = ::CreateWindowEx(
0, //m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL ? WS_EX_TOOLWINDOW : 0,
Console::m_szConsoleClass,
m_strWindowTitle.c_str(),
dwWindowStyle,
((m_nX == -1) || (m_nY == -1)) ? CW_USEDEFAULT : 0,
0,
0,
0,
m_hwndInvisParent,
NULL,
ghInstance,
NULL)) == NULL) {
return FALSE;
}
::SetWindowLongPtr( m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
if ((m_nX == -1) || (m_nY == -1)) {
RECT rectWindow;
::GetWindowRect(m_hWnd, &rectWindow);
m_nX = (int)rectWindow.left;
m_nY = (int)rectWindow.top;
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::CreateNewFont() {
// create a new font
if (m_hFontOld) ::SelectObject(m_hdcConsole, m_hFontOld);
if (m_hFont) ::DeleteObject(m_hFont);
m_hFont = ::CreateFont(
-MulDiv(m_dwFontSize, ::GetDeviceCaps(m_hdcConsole, LOGPIXELSY), 72),
0,
0,
0,
m_bBold ? FW_BOLD : 0,
m_bItalic,
FALSE,
FALSE,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH,
m_strFontName.c_str());
m_hFontOld = (HFONT)::SelectObject(m_hdcConsole, m_hFont);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::CreateNewBrush() {
// create a new background brush
if (m_hBkBrush) ::DeleteObject(m_hBkBrush);
m_hBkBrush = ::CreateSolidBrush(m_crBackground);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::CreateCursor() {
switch (m_dwCursorStyle) {
case CURSOR_STYLE_XTERM :
m_pCursor = (Cursor*)new XTermCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_BLOCK :
m_pCursor = (Cursor*)new BlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_NBBLOCK :
m_pCursor = (Cursor*)new NBBlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_PULSEBLOCK :
m_pCursor = (Cursor*)new PulseBlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_BAR :
m_pCursor = (Cursor*)new BarCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_CONSOLE :
m_pCursor = (Cursor*)new ConsoleCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_NBHLINE :
m_pCursor = (Cursor*)new NBHLineCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_HLINE :
m_pCursor = (Cursor*)new HLineCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_VLINE :
m_pCursor = (Cursor*)new VLineCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_RECT :
m_pCursor = (Cursor*)new RectCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_NBRECT :
m_pCursor = (Cursor*)new NBRectCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_PULSERECT :
m_pCursor = (Cursor*)new PulseRectCursor(m_hWnd, m_hdcConsole, m_crCursorColor);
break;
case CURSOR_STYLE_FADEBLOCK :
m_pCursor = (Cursor*)new FadeBlockCursor(m_hWnd, m_hdcConsole, m_crCursorColor, m_crBackground);
break;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::CreateOffscreenBuffers() {
HDC hdcDesktop = ::GetDCEx(m_hWnd, NULL, 0);
// create new window bitmap
if (m_hbmpConsoleOld) ::SelectObject(m_hdcConsole, m_hbmpConsoleOld);
if (m_hbmpConsole) ::DeleteObject(m_hbmpConsole);
m_hbmpConsole = ::CreateCompatibleBitmap(hdcDesktop, m_nClientWidth, m_nClientHeight);
m_hbmpConsoleOld = (HBITMAP)::SelectObject(m_hdcConsole, m_hbmpConsole);
if (m_hbmpWindowOld) ::SelectObject(m_hdcWindow, m_hbmpWindowOld);
if (m_hbmpWindow) ::DeleteObject(m_hbmpWindow);
m_hbmpWindow = ::CreateCompatibleBitmap(hdcDesktop, m_nClientWidth, m_nClientHeight);
m_hbmpWindowOld = (HBITMAP)::SelectObject(m_hdcWindow, m_hbmpWindow);
// create selection bitmap
if (m_hbmpSelectionOld) ::SelectObject(m_hdcSelection, m_hbmpSelectionOld);
if (m_hbmpSelection) ::DeleteObject(m_hbmpSelection);
m_hbmpSelection = ::CreateCompatibleBitmap(m_hdcWindow, m_nClientWidth, m_nClientHeight);
m_hbmpSelectionOld = (HBITMAP)::SelectObject(m_hdcSelection, m_hbmpSelection);
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = m_nClientWidth;
rect.bottom = m_nClientHeight;
::FillRect(m_hdcSelection, &rect, m_hbrushSelection);
::ReleaseDC(m_hWnd, hdcDesktop);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#if 0
void Console::CreateBackgroundBitmap() {
USES_CONVERSION;
if (m_hbmpBackgroundOld) ::SelectObject(m_hdcBackground, m_hbmpBackgroundOld);
if (m_hbmpBackground) ::DeleteObject(m_hbmpBackground);
if (m_hdcBackground) ::DeleteDC(m_hdcBackground);
if (!m_bBitmapBackground) return;
// determine the total size of the background bitmap
DWORD dwPrimaryDisplayWidth = ::GetSystemMetrics(SM_CXSCREEN);
DWORD dwPrimaryDisplayHeight = ::GetSystemMetrics(SM_CYSCREEN);
DWORD dwBackgroundWidth = 0;
DWORD dwBackgroundHeight = 0;
if (m_bRelativeBackground) {
if (g_bWin2000) {
// Win2K and later can handle multiple monitors
dwBackgroundWidth = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
dwBackgroundHeight = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
// get offsets for virtual display
m_nBackgroundOffsetX = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
m_nBackgroundOffsetY = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
} else {
// WinNT compatibility (hope it works, I didn't test it)
dwBackgroundWidth = dwPrimaryDisplayWidth;
dwBackgroundHeight = dwBackgroundHeight;
}
} else {
dwBackgroundWidth = m_nClientWidth;
dwBackgroundHeight = m_nClientHeight;
}
// now, load the image...
fipImage image;
IMAGE_DATA imageData;
if (!image.load(T2A(m_strBackgroundFile.c_str()))) {
m_bBitmapBackground = FALSE;
return;
}
imageData.hdcImage = NULL;
imageData.dwImageWidth = image.getWidth();
imageData.dwImageHeight = image.getHeight();
image.convertTo24Bits();
// ... if needed, tint the background image
if (m_bTintSet) {
BYTE* pPixels = image.accessPixels();
BYTE* pPixelsEnd = pPixels + 3*image.getWidth()*image.getHeight();
BYTE* pPixelSubel = pPixels;
while (pPixelSubel < pPixelsEnd) {
*pPixelSubel = (BYTE) ((unsigned long)(*pPixelSubel * (100 - m_byTintOpacity) + m_byTintB*m_byTintOpacity)/100);
++pPixelSubel;
*pPixelSubel = (BYTE) ((unsigned long)(*pPixelSubel * (100 - m_byTintOpacity) + m_byTintG*m_byTintOpacity)/100);
++pPixelSubel;
*pPixelSubel = (BYTE) ((unsigned long)(*pPixelSubel * (100 - m_byTintOpacity) + m_byTintR*m_byTintOpacity)/100);
++pPixelSubel;
}
}
// create the basic image
HBITMAP hbmpImage = NULL;
HBITMAP hbmpImageOld = NULL;
if (m_dwBackgroundStyle == BACKGROUND_STYLE_RESIZE) {
if (m_bRelativeBackground) {
if (m_bExtendBackground) {
imageData.dwImageWidth = dwBackgroundWidth;
imageData.dwImageHeight = dwBackgroundHeight;
} else {
imageData.dwImageWidth = dwPrimaryDisplayWidth;
imageData.dwImageHeight = dwPrimaryDisplayHeight;
}
} else {
imageData.dwImageWidth = (DWORD)m_nClientWidth;
imageData.dwImageHeight = (DWORD)m_nClientHeight;
}
if ((image.getWidth() != imageData.dwImageWidth) || (image.getHeight() != imageData.dwImageHeight)) {
image.rescale(imageData.dwImageWidth, imageData.dwImageHeight, FILTER_LANCZOS3);
}
}
// now, create a DC compatible with the screen and create the basic bitmap
HDC hdcDesktop = ::GetDCEx(m_hWnd, NULL, 0);
imageData.hdcImage = ::CreateCompatibleDC(hdcDesktop);
hbmpImage = ::CreateDIBitmap(
hdcDesktop,
image.getInfoHeader(),
CBM_INIT,
image.accessPixels(),
image.getInfo(),
DIB_RGB_COLORS);
hbmpImageOld= (HBITMAP)::SelectObject(imageData.hdcImage, hbmpImage);
::ReleaseDC(m_hWnd, hdcDesktop);
// create the background image
m_hdcBackground = ::CreateCompatibleDC(imageData.hdcImage);
m_hbmpBackground = ::CreateCompatibleBitmap(imageData.hdcImage, dwBackgroundWidth, dwBackgroundHeight);
m_hbmpBackgroundOld = (HBITMAP)::SelectObject(m_hdcBackground, m_hbmpBackground);
RECT rectBackground;
rectBackground.left = 0;
rectBackground.top = 0;
rectBackground.right = dwBackgroundWidth;
rectBackground.bottom = dwBackgroundHeight;
// fill the background with the proper background color in case the
// bitmap doesn't cover the entire background,
COLORREF crBackground;
if (m_dwTransparency == TRANSPARENCY_FAKE) {
// get desktop background color
HKEY hkeyColors;
if (::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Colors"), 0, KEY_READ, &hkeyColors) == ERROR_SUCCESS) {
TCHAR szData[MAX_PATH];
DWORD dwDataSize = MAX_PATH;
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
::ZeroMemory(szData, sizeof(szData));
::RegQueryValueEx(hkeyColors, _T("Background"), NULL, NULL, (BYTE*)szData, &dwDataSize);
_stscanf(szData, _T("%i %i %i"), &r, &g, &b);
crBackground = RGB(r, g, b);
::RegCloseKey(hkeyColors);
}
} else {
::CopyMemory(&crBackground, &m_crBackground, sizeof(COLORREF));
}
HBRUSH hBkBrush = ::CreateSolidBrush(crBackground);
::FillRect(m_hdcBackground, &rectBackground, hBkBrush);
::DeleteObject(hBkBrush);
if (m_dwBackgroundStyle == BACKGROUND_STYLE_TILE) {
// we're tiling the image, starting at coordinates (0, 0) of the virtual screen
DWORD dwX = 0;
DWORD dwY = 0;
DWORD dwImageOffsetX = 0;
DWORD dwImageOffsetY = imageData.dwImageHeight + (m_nBackgroundOffsetY - (int)imageData.dwImageHeight*(m_nBackgroundOffsetY/(int)imageData.dwImageHeight));
while (dwY < dwBackgroundHeight) {
dwX = 0;
dwImageOffsetX = imageData.dwImageWidth + (m_nBackgroundOffsetX - (int)imageData.dwImageWidth*(m_nBackgroundOffsetX/(int)imageData.dwImageWidth));
while (dwX < dwBackgroundWidth) {
::BitBlt(
m_hdcBackground,
dwX,
dwY,
imageData.dwImageWidth,
imageData.dwImageHeight,
imageData.hdcImage,
dwImageOffsetX,
dwImageOffsetY,
SRCCOPY);
dwX += imageData.dwImageWidth - dwImageOffsetX;
dwImageOffsetX = 0;
}
dwY += imageData.dwImageHeight - dwImageOffsetY;
dwImageOffsetY = 0;
}
} else if (m_bExtendBackground || !m_bRelativeBackground) {
switch (m_dwBackgroundStyle) {
case BACKGROUND_STYLE_RESIZE :
::BitBlt(
m_hdcBackground,
0,
0,
dwBackgroundWidth,
dwBackgroundHeight,
imageData.hdcImage,
0,
0,
SRCCOPY);
break;
case BACKGROUND_STYLE_CENTER :
::BitBlt(
m_hdcBackground,
(dwBackgroundWidth <= imageData.dwImageWidth) ? 0 : (dwBackgroundWidth - imageData.dwImageWidth)/2,
(dwBackgroundHeight <= imageData.dwImageHeight) ? 0 : (dwBackgroundHeight - imageData.dwImageHeight)/2,
imageData.dwImageWidth,
imageData.dwImageHeight,
imageData.hdcImage,
(dwBackgroundWidth < imageData.dwImageWidth) ? (imageData.dwImageWidth - dwBackgroundWidth)/2 : 0,
(dwBackgroundHeight < imageData.dwImageHeight) ? (imageData.dwImageHeight - dwBackgroundHeight)/2 : 0,
SRCCOPY);
break;
}
} else {
::EnumDisplayMonitors(NULL, NULL, Console::BackgroundEnumProc, (DWORD)&imageData);
}
::SelectObject(imageData.hdcImage, hbmpImageOld);
::DeleteObject(hbmpImage);
::DeleteDC(imageData.hdcImage);
}
#endif
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#if 0
BOOL CALLBACK Console::BackgroundEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
IMAGE_DATA* pImageData = (IMAGE_DATA*)dwData;
DWORD dwDisplayWidth = lprcMonitor->right - lprcMonitor->left;
DWORD dwDisplayHeight = lprcMonitor->bottom - lprcMonitor->top;
DWORD dwPrimaryDisplayWidth = ::GetSystemMetrics(SM_CXSCREEN);
DWORD dwPrimaryDisplayHeight = ::GetSystemMetrics(SM_CYSCREEN);
// center the image according to current display's size and position
switch (g_pConsole->m_dwBackgroundStyle) {
case BACKGROUND_STYLE_RESIZE :
::BitBlt(
g_pConsole->m_hdcBackground,
(dwDisplayWidth <= dwPrimaryDisplayWidth) ? lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX : lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX + (dwDisplayWidth - dwPrimaryDisplayWidth)/2,
(dwDisplayHeight <= dwPrimaryDisplayHeight) ? lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY : lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY + (dwDisplayHeight - dwPrimaryDisplayHeight)/2,
dwDisplayWidth,
dwDisplayHeight,
pImageData->hdcImage,
(dwDisplayWidth < dwPrimaryDisplayWidth) ? (dwPrimaryDisplayWidth - dwDisplayWidth)/2 : 0,
(dwDisplayHeight < dwPrimaryDisplayHeight) ? (dwPrimaryDisplayHeight - dwDisplayHeight)/2 : 0,
SRCCOPY);
break;
case BACKGROUND_STYLE_CENTER :
::BitBlt(
g_pConsole->m_hdcBackground,
(dwDisplayWidth <= pImageData->dwImageWidth) ? lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX : lprcMonitor->left-g_pConsole->m_nBackgroundOffsetX + (dwDisplayWidth - pImageData->dwImageWidth)/2,
(dwDisplayHeight <= pImageData->dwImageHeight) ? lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY : lprcMonitor->top-g_pConsole->m_nBackgroundOffsetY + (dwDisplayHeight - pImageData->dwImageHeight)/2,
dwDisplayWidth,
dwDisplayHeight,
pImageData->hdcImage,
(dwDisplayWidth < pImageData->dwImageWidth) ? (pImageData->dwImageWidth - dwDisplayWidth)/2 : 0,
(dwDisplayHeight < pImageData->dwImageHeight) ? (pImageData->dwImageHeight - dwDisplayHeight)/2 : 0,
SRCCOPY);
break;
}
return TRUE;
}
#endif
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::GetTextSize() {
TEXTMETRIC textMetric;
::GetTextMetrics(m_hdcConsole, &textMetric);
m_nCharHeight = textMetric.tmHeight;
if (!(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
// fixed pitch font (TMPF_FIXED_PITCH is cleared!!!)
m_nCharWidth = textMetric.tmAveCharWidth;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::GetBordersDimensions() {
WINDOWINFO wndInfo;
TITLEBARINFO titlebarInfo;
::ZeroMemory(&wndInfo, sizeof(WINDOWINFO));
::ZeroMemory(&titlebarInfo, sizeof(TITLEBARINFO));
wndInfo.cbSize = sizeof(WINDOWINFO);
titlebarInfo.cbSize = sizeof(TITLEBARINFO);
::GetWindowInfo(m_hWnd, &wndInfo);
::GetTitleBarInfo(m_hWnd, &titlebarInfo);
m_nXBorderSize = wndInfo.cxWindowBorders;
m_nYBorderSize = wndInfo.cyWindowBorders;
m_nCaptionSize = (titlebarInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE) ? 0 : titlebarInfo.rcTitleBar.bottom - titlebarInfo.rcTitleBar.top;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::CalcWindowSize() {
m_nClientHeight = m_dwRows * m_nCharHeight + 2*m_nInsideBorder;
if (m_nCharWidth > 0) {
// fixed pitch font
m_nClientWidth = m_dwColumns * m_nCharWidth + 2*m_nInsideBorder;
} else {
// variable pitch font
int nCharWidth;
::GetCharWidth32(m_hdcConsole, _TCHAR('m'), _TCHAR('m'), &nCharWidth);
m_nClientWidth = m_dwColumns * nCharWidth;
}
switch (m_dwWindowBorder) {
case BORDER_NONE :
m_nWindowHeight = m_nClientHeight;
m_nWindowWidth = m_nClientWidth;
break;
case BORDER_REGULAR : {
m_nWindowHeight = m_nClientHeight + m_nCaptionSize + 2*m_nYBorderSize;
m_nWindowWidth = m_nClientWidth + 2 * m_nXBorderSize;
break;
}
case BORDER_THIN :
m_nWindowHeight = m_nClientHeight + 2*m_nYBorderSize;
m_nWindowWidth = m_nClientWidth + 2*m_nXBorderSize;
}
if (m_bShowScrollbar) m_nWindowWidth += m_nScrollbarWidth;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#if 0
void Console::SetWindowTransparency() {
// set alpha transparency (Win2000 and later only!)
if (g_bWin2000 && ((m_dwTransparency == TRANSPARENCY_ALPHA) || (m_dwTransparency == TRANSPARENCY_COLORKEY))) {
::SetWindowLong(m_hWnd, GWL_EXSTYLE, ::GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
g_pfnSetLayeredWndAttr(m_hWnd, m_crBackground, m_byAlpha, m_dwTransparency == TRANSPARENCY_ALPHA ? LWA_ALPHA : LWA_COLORKEY);
} else if (m_dwTransparency == TRANSPARENCY_FAKE) {
// get wallpaper settings
HKEY hkeyDesktop;
if (::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"), 0, KEY_READ, &hkeyDesktop) == ERROR_SUCCESS) {
TCHAR szData[MAX_PATH];
DWORD dwDataSize = MAX_PATH;
DWORD dwWallpaperStyle;
DWORD dwTileWallpaper;
::ZeroMemory(szData, sizeof(szData));
::RegQueryValueEx(hkeyDesktop, _T("Wallpaper"), NULL, NULL, (BYTE*)szData, &dwDataSize);
if (_tcslen(szData) > 0) {
m_bBitmapBackground = TRUE;
m_strBackgroundFile = szData;
m_bRelativeBackground = TRUE;
m_bExtendBackground = FALSE;
// get wallpaper style and tile flag
dwDataSize = MAX_PATH;
::ZeroMemory(szData, sizeof(szData));
::RegQueryValueEx(hkeyDesktop, _T("WallpaperStyle"), NULL, NULL, (BYTE*)szData, &dwDataSize);
dwWallpaperStyle = _ttoi(szData);
dwDataSize = MAX_PATH;
::ZeroMemory(szData, sizeof(szData));
::RegQueryValueEx(hkeyDesktop, _T("TileWallpaper"), NULL, NULL, (BYTE*)szData, &dwDataSize);
dwTileWallpaper = _ttoi(szData);
if (dwTileWallpaper == 1) {
m_dwBackgroundStyle = BACKGROUND_STYLE_TILE;
} else {
if (dwWallpaperStyle == 0) {
m_dwBackgroundStyle = BACKGROUND_STYLE_CENTER;
} else {
m_dwBackgroundStyle = BACKGROUND_STYLE_RESIZE;
}
}
}
::RegCloseKey(hkeyDesktop);
}
}
}
#endif
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::SetScrollbarStuff() {
if (m_bUseTextBuffer) {
m_bShowScrollbar = m_dwBufferRows > m_dwRows;
} else {
m_bShowScrollbar = FALSE;
}
// we don't call InitializeFlatSB due to some problems on Win2k, Windowblinds and new-style scrollbars
if (m_nScrollbarStyle != FSB_REGULAR_MODE) ::InitializeFlatSB(m_hWnd);
::FlatSB_ShowScrollBar(m_hWnd, SB_VERT, m_bShowScrollbar);
::FlatSB_SetScrollRange(m_hWnd, SB_VERT, 0, m_dwBufferRows-m_dwRows, FALSE);
// set scrollbar properties
::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_VSTYLE, m_nScrollbarStyle, FALSE);
::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_VBKGCOLOR, m_crScrollbarColor, FALSE);
::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_CXVSCROLL , m_nScrollbarWidth, FALSE);
::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_CYVSCROLL, m_nScrollbarButtonHeight, FALSE);
::FlatSB_SetScrollProp(m_hWnd, WSB_PROP_CYVTHUMB, m_nScrollbarThunmbHeight, TRUE);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::SetDefaultConsoleColors() {
m_arrConsoleColors[0] = 0x000000;
m_arrConsoleColors[1] = 0x800000;
m_arrConsoleColors[2] = 0x008000;
m_arrConsoleColors[3] = 0x808000;
m_arrConsoleColors[4] = 0x000080;
m_arrConsoleColors[5] = 0x800080;
m_arrConsoleColors[6] = 0x008080;
m_arrConsoleColors[7] = 0xC0C0C0;
m_arrConsoleColors[8] = 0x808080;
m_arrConsoleColors[9] = 0xFF0000;
m_arrConsoleColors[10] = 0x00FF00;
m_arrConsoleColors[11] = 0xFFFF00;
m_arrConsoleColors[12] = 0x0000FF;
m_arrConsoleColors[13] = 0xFF00FF;
m_arrConsoleColors[14] = 0x00FFFF;
m_arrConsoleColors[15] = 0xFFFFFF;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::SetWindowSizeAndPosition() {
// set window position
#if 0
DWORD dwScreenWidth = ::GetSystemMetrics(g_bWin2000 ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
DWORD dwScreenHeight = ::GetSystemMetrics(g_bWin2000 ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
DWORD dwTop = ::GetSystemMetrics(g_bWin2000 ? SM_YVIRTUALSCREEN : 0);
DWORD dwLeft = ::GetSystemMetrics(g_bWin2000 ? SM_XVIRTUALSCREEN : 0);
#else
DWORD dwScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
DWORD dwScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
DWORD dwTop = ::GetSystemMetrics(0);
DWORD dwLeft = ::GetSystemMetrics(0);
#endif
switch (m_dwDocked) {
case DOCK_TOP_LEFT:
// top left
m_nX = dwLeft;
m_nY = dwTop;
break;
case DOCK_TOP_RIGHT:
// top right
m_nX = dwScreenWidth - m_nWindowWidth;
m_nY = dwTop;
break;
case DOCK_BOTTOM_RIGHT:
// bottom right
m_nX = dwScreenWidth - m_nWindowWidth;
m_nY = dwScreenHeight - m_nWindowHeight;
break;
case DOCK_BOTTOM_LEFT:
// bottom left
m_nX = dwLeft;
m_nY = dwScreenHeight - m_nWindowHeight;
break;
}
HWND hwndZ = 0;
switch (m_dwCurrentZOrder) {
case Z_ORDER_REGULAR : hwndZ = HWND_NOTOPMOST; break;
case Z_ORDER_ONTOP : hwndZ = HWND_TOPMOST; break;
case Z_ORDER_ONBOTTOM : hwndZ = HWND_BOTTOM; break;
default : return;
}
::SetWindowPos(
m_hWnd,
hwndZ,
m_nX,
m_nY,
m_nWindowWidth,
m_nWindowHeight,
0);
UpdateOnTopMenuItem();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::SetWindowIcons() {
HICON hOldIcon = NULL;
if (m_strIconFilename.length() > 0) {
// custom icon, try loading it...
if ((m_hSmallIcon = (HICON)::LoadImage(NULL, m_strIconFilename.c_str(), IMAGE_ICON, 16, 16, LR_LOADFROMFILE)) != NULL) {
// icon file exists, load and set the big icon as well
m_hBigIcon = (HICON)::LoadImage(NULL, m_strIconFilename.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
hOldIcon = (HICON)::SendMessage(m_hWnd, WM_SETICON, ICON_BIG, (LPARAM)m_hBigIcon);
if (hOldIcon) ::DestroyIcon(hOldIcon);
} else {
m_hSmallIcon = (HICON)::LoadImage(ghInstance, MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON, 16, 16, 0);
}
} else {
m_hSmallIcon = (HICON)::LoadImage(ghInstance, MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON, 16, 16, 0);
}
hOldIcon = (HICON)::SendMessage(m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)m_hSmallIcon);
if (hOldIcon) ::DestroyIcon(hOldIcon);
SetTrayIcon(m_dwTaskbarButton == TASKBAR_BUTTON_TRAY ? NIM_ADD : NIM_DELETE);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::SetTrayIcon(DWORD dwMessage) {
NOTIFYICONDATA tnd;
tstring strToolTip(m_strWindowTitle);
tnd.cbSize = sizeof(NOTIFYICONDATA);
tnd.hWnd = m_hWnd;
tnd.uID = TRAY_ICON_ID;
tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
tnd.uCallbackMessage = WM_TRAY_NOTIFY;
tnd.hIcon = m_hSmallIcon;
if (strToolTip.length() > 63) {
strToolTip.resize(59);
strToolTip += _T(" ...");
// DWORD dw = strToolTip.length();
}
_tcscpy(tnd.szTip, strToolTip.c_str());
return ::Shell_NotifyIcon(dwMessage, &tnd);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::DestroyCursor() {
if (m_pCursor)
{
delete m_pCursor;
m_pCursor = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::EditConfigFile() {
// prepare editor parameters
tstring strParams(m_strConfigEditorParams);
if (strParams.length() == 0) {
// no params, just use the config file
strParams = m_strConfigFile;
} else {
tstring::size_type nPos = strParams.find(_T("%f"));
if (nPos == tstring::npos) {
// no '%f' in editor params, concatenate config file name
strParams += _T(" ");
strParams += m_strConfigFile;
} else {
// replace '%f' with config file name
strParams = strParams.replace(nPos, 2, m_strConfigFile);
}
}
// start editor
::ShellExecute(NULL, NULL, m_strConfigEditor.c_str(), strParams.c_str(), NULL, SW_SHOWNORMAL);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::ReloadSettings() {
m_bInitializing = TRUE;
m_bReloading = TRUE;
// suspend console monitor thread
::SuspendThread(m_hMonitorThread);
::KillTimer(m_hWnd, TIMER_REPAINT_CHANGE);
if (m_dwMasterRepaintInt) ::KillTimer(m_hWnd, TIMER_REPAINT_MASTER);
// hide Windows console
::ShowWindow(m_hWndConsole, SW_HIDE);
// destroy icons
SetTrayIcon(NIM_DELETE);
if (m_hSmallIcon) ::DestroyIcon(m_hSmallIcon);
if (m_hBigIcon) ::DestroyIcon(m_hBigIcon);
// destroy cursor
DestroyCursor();
// destory menus
::DestroyMenu(m_hConfigFilesMenu);
::DestroyMenu(m_hPopupMenu);
// uninitialize flat scrollbars
if (m_nScrollbarStyle != FSB_REGULAR_MODE) ::UninitializeFlatSB(m_hWnd);
// destory window
::DestroyWindow(m_hWnd);
if (m_hwndInvisParent) ::DestroyWindow(m_hwndInvisParent);
// set default values
m_strShell = _T("");
m_strConfigEditor = _T("notepad.exe");
m_strConfigEditorParams = _T("");
m_dwReloadNewConfig = m_dwReloadNewConfigDefault;
m_hwndInvisParent = NULL;
m_dwMasterRepaintInt = 500;
m_dwChangeRepaintInt = 50;
m_strIconFilename = _T("");
m_hSmallIcon = NULL;
m_hBigIcon = NULL;
m_hPopupMenu = NULL;
m_hConfigFilesMenu = NULL;
m_bPopupMenuDisabled = FALSE;
m_strWindowTitle = m_strWindowTitleDefault;
m_strWindowTitleCurrent = m_strWindowTitleDefault;
m_strFontName = _T("Courier New");
m_dwFontSize = 10;
m_bBold = FALSE;
m_bItalic = FALSE;
m_bUseFontColor = FALSE;
m_crFontColor = RGB(0, 0, 0);
m_nWindowWidth = 0;
m_nWindowHeight = 0;
m_nXBorderSize = 5;
m_nYBorderSize = 5;
m_nCaptionSize = 0;
m_nClientWidth = 0;
m_nClientHeight = 0;
m_nCharHeight = 0;
m_nCharWidth = 0;
m_dwWindowBorder = BORDER_REGULAR;
m_bShowScrollbar = TRUE;
m_nScrollbarStyle = FSB_REGULAR_MODE;
m_crScrollbarColor = ::GetSysColor(COLOR_3DHILIGHT);
m_nScrollbarWidth = ::GetSystemMetrics(SM_CXVSCROLL);
m_nScrollbarButtonHeight= ::GetSystemMetrics(SM_CYVSCROLL);
m_nScrollbarThunmbHeight= ::GetSystemMetrics(SM_CYVTHUMB);
m_dwTaskbarButton = TASKBAR_BUTTON_NORMAL;
m_bMouseDragable = TRUE;
m_nSnapDst = 10;
m_dwDocked = DOCK_NONE;
m_dwOriginalZOrder = Z_ORDER_REGULAR;
m_dwCurrentZOrder = Z_ORDER_REGULAR;
m_dwTransparency = TRANSPARENCY_NONE;
m_byAlpha = 150;
m_byInactiveAlpha = 150;
m_crBackground = RGB(0, 0, 0);
m_crConsoleBackground = RGB(0, 0, 0);
m_bTintSet = FALSE;
m_byTintOpacity = 50;
m_byTintR = 0;
m_byTintG = 0;
m_byTintB = 0;
m_bBitmapBackground = FALSE;
m_strBackgroundFile = _T("");
m_dwBackgroundStyle = BACKGROUND_STYLE_RESIZE;
m_bRelativeBackground = FALSE;
m_bExtendBackground = FALSE;
m_bHideWindow = FALSE;
m_bHideConsole = TRUE;
m_dwCursorStyle = CURSOR_STYLE_CONSOLE;
m_bStartMinimized = FALSE;
m_crCursorColor = RGB(255, 255, 255);
m_bCursorVisible = TRUE;
m_dwRows = 50;
m_dwColumns = 80;
m_dwBufferRows = 500;
m_bUseTextBuffer = TRUE;
m_bCopyOnSelect = FALSE;
m_nTextColor = 15;
m_nTextBgColor = 0;
SetDefaultConsoleColors();
GetOptions();
CreateConsoleWindow();
SetupMenus();
CreateNewFont();
CreateNewBrush();
// SetWindowTransparency();
SetWindowIcons();
CreateCursor();
RefreshStdOut();
GetTextSize();
GetBordersDimensions();
InitConsoleWndSize(m_dwColumns);
ResizeConsoleWindow();
// ShowHideConsole();
m_bInitializing = FALSE;
m_bReloading = FALSE;
RefreshScreenBuffer();
::CopyMemory(m_pScreenBuffer, m_pScreenBufferNew, sizeof(CHAR_INFO) * m_dwRows * m_dwColumns);
RepaintWindow();
if (m_dwMasterRepaintInt) ::SetTimer(m_hWnd, TIMER_REPAINT_MASTER, m_dwMasterRepaintInt, NULL);
if (m_bStartMinimized) {
if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) {
m_bHideWindow = TRUE;
} else {
::ShowWindow(m_hWnd, SW_MINIMIZE);
}
} else {
::ShowWindow(m_hWnd, SW_SHOW);
}
::SetForegroundWindow(m_hWnd);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::StartShellProcess() {
#if 0
if (m_strShell.length() == 0) {
TCHAR szComspec[MAX_PATH];
if (::GetEnvironmentVariable(_T("COMSPEC"), szComspec, MAX_PATH) > 0) {
m_strShell = szComspec;
} else {
m_strShell = _T("cmd.exe");
}
}
tstring strShellCmdLine(m_strShell);
if (m_strShellCmdLine.length() > 0) {
strShellCmdLine += _T(" ");
strShellCmdLine += m_strShellCmdLine;
}
// strShellCmdLine = "cmd.exe";
// create the console window
TCHAR szConsoleTitle[MAX_PATH];
::AllocConsole();
// we use this to avoid possible problems with multiple console instances running
_stprintf(szConsoleTitle, _T("%i"), ::GetCurrentThreadId());
::SetConsoleTitle(szConsoleTitle);
m_hStdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
while ((m_hWndConsole = ::FindWindow(NULL, szConsoleTitle)) == NULL) ::Sleep(50);
::SetConsoleTitle(m_strWinConsoleTitle.c_str());
#endif
// this is a little hack needed to support columns greater than standard 80
RefreshStdOut();
InitConsoleWndSize(80);
ResizeConsoleWindow();
#if 0
::SetConsoleCtrlHandler(Console::CtrlHandler, TRUE);
// setup the start up info struct
PROCESS_INFORMATION pi;
STARTUPINFO si;
::ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
if (!::CreateProcess(
NULL,
(TCHAR*)strShellCmdLine.c_str(),
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&si,
&pi)) {
return FALSE;
}
if (m_dwHideConsoleTimeout > 0) {
::ShowWindow(m_hWndConsole, SW_MINIMIZE);
::SetTimer(m_hWnd, TIMER_SHOW_HIDE_CONSOLE, m_dwHideConsoleTimeout, NULL);
} else {
ShowHideConsole();
}
// close main thread handle
::CloseHandle(pi.hThread);
// set handles
m_hQuitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
m_hConsoleProcess = pi.hProcess;
#endif
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::RefreshStdOut() {
#if 0
if (m_hStdOutFresh) ::CloseHandle(m_hStdOutFresh);
m_hStdOutFresh = ::CreateFile(_T("CONOUT$"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::RefreshScreenBuffer() {
// if we're initializing, do nothing
if (m_bInitializing) return;
// ::GetConsoleScreenBufferInfo(m_hStdOutFresh, &m_csbiConsole);
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = (int)m_csbiConsole.srWindow.Top;
::FlatSB_SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE);
#if 0
if ((m_csbiConsole.srWindow.Right - m_csbiConsole.srWindow.Left + 1 != m_dwColumns) || (m_csbiConsole.srWindow.Bottom - m_csbiConsole.srWindow.Top + 1 != m_dwRows) || (m_csbiConsole.dwSize.Y != m_dwBufferRows)) {
m_dwColumns = m_csbiConsole.srWindow.Right - m_csbiConsole.srWindow.Left + 1;
m_dwRows = m_csbiConsole.srWindow.Bottom - m_csbiConsole.srWindow.Top + 1;
ResizeConsoleWindow();
}
COORD coordBufferSize;
COORD coordStart;
SMALL_RECT srRegion;
coordStart.X = 0;
coordStart.Y = 0;
coordBufferSize.X = m_dwColumns;
coordBufferSize.Y = m_dwRows;
srRegion.Top = m_csbiConsole.srWindow.Top;
srRegion.Left = 0;
srRegion.Bottom = m_csbiConsole.srWindow.Top + m_dwRows - 1;
srRegion.Right = m_dwColumns - 1;
DEL_ARR(m_pScreenBufferNew);
m_pScreenBufferNew = new CHAR_INFO[m_dwRows * m_dwColumns];
::ZeroMemory( m_pScreenBufferNew, m_dwRows * m_dwColumns * sizeof(CHAR_INFO));
for (int i=0; i<m_dwRows*m_dwColumns; i++) { m_pScreenBufferNew[i].Char.AsciiChar = '0' + i%10; m_pScreenBufferNew[i].Attributes = 15; }
::ReadConsoleOutput(m_hStdOutFresh, m_pScreenBufferNew, coordBufferSize, coordStart, &srRegion);
// set console window title
TCHAR szWinConsoleTitle[MAX_PATH+1];
::GetConsoleTitle(szWinConsoleTitle, MAX_PATH);
tstring strWinConsoleTitle(szWinConsoleTitle);
tstring strConsoleTitle(_T(""));
// Here we decide about updating Console window title.
// There are 2 possibilities:
if (m_strWinConsoleTitle.compare(0, m_strWinConsoleTitle.length(), strWinConsoleTitle, 0, m_strWinConsoleTitle.length()) == 0) {
// 1. Windows console title starts with the original title, just see if
// windows titles differ, and if they do, update it.
if ((m_strWindowTitle.length() == 0) &&
(strWinConsoleTitle[m_strWinConsoleTitle.length()] == ' ') &&
(strWinConsoleTitle[m_strWinConsoleTitle.length()+1] == '-')) {
strConsoleTitle = strWinConsoleTitle.substr(m_strWinConsoleTitle.length()+3);
} else {
strConsoleTitle = m_strWindowTitle + strWinConsoleTitle.substr(m_strWinConsoleTitle.length());
}
} else {
// 2. Windows console title is completely changed. To set Console title,
// we need to get Windows console title and concatenate it to our
// original Console title (if it changed since the last update)
if (m_strWindowTitle.length() == 0) {
strConsoleTitle = strWinConsoleTitle;
} else {
strConsoleTitle = m_strWindowTitle + tstring(_T(" - ")) + strWinConsoleTitle;
}
}
if (m_strWindowTitleCurrent.compare(strConsoleTitle) != 0) {
m_strWindowTitleCurrent = strConsoleTitle;
::SetWindowText(m_hWnd, m_strWindowTitleCurrent.c_str());
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::InitConsoleWndSize(DWORD dwColumns) {
if (m_nTextSelection) ClearSelection();
// get max console size
// COORD coordMaxSize;
// coordMaxSize = ::GetLargestConsoleWindowSize(m_hStdOutFresh);
// calc max window size
RECT rectDesktop;
GetDesktopRect(rectDesktop);
DWORD dwMaxColumns = (rectDesktop.right - rectDesktop.left - 2*m_nInsideBorder - 2*m_nXBorderSize - m_nScrollbarWidth)/m_nCharWidth;
DWORD dwMaxRows = (rectDesktop.bottom - rectDesktop.top - 2*m_nInsideBorder - m_nYBorderSize - m_nCaptionSize)/m_nCharHeight;
// if (m_dwColumns == 0) m_dwColumns = coordMaxSize.X < dwMaxColumns ? coordMaxSize.X : dwMaxColumns;
// if (m_dwRows == 0) m_dwRows = coordMaxSize.Y < dwMaxRows ? coordMaxSize.Y : dwMaxRows;
if (m_dwColumns == 0) m_dwColumns = dwMaxColumns;
if (m_dwRows == 0) m_dwRows = dwMaxRows;
if (m_dwBufferRows < m_dwRows) m_dwBufferRows = m_dwRows;
COORD coordConsoleSize;
coordConsoleSize.X = (SHORT)dwColumns;
coordConsoleSize.Y = (SHORT)m_dwBufferRows;
SMALL_RECT srConsoleRect;
srConsoleRect.Top = srConsoleRect.Left =0;
// srConsoleRect.Right = dwColumns - 1;
// srConsoleRect.Bottom= m_dwRows - 1;
#if 0
CONSOLE_SCREEN_BUFFER_INFO csbi;
::GetConsoleScreenBufferInfo(m_hStdOutFresh, &csbi);
if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) dwColumns * m_dwBufferRows) {
::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect);
::SetConsoleScreenBufferSize(m_hStdOutFresh, coordConsoleSize);
} else if (((DWORD)csbi.dwSize.X < dwColumns) || ((DWORD)csbi.dwSize.Y < m_dwBufferRows) || ((DWORD)(csbi.srWindow.Bottom - csbi.srWindow.Top + 1) != m_dwRows)) {
::SetConsoleScreenBufferSize(m_hStdOutFresh, coordConsoleSize);
::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect);
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::ResizeConsoleWindow() {
m_bInitializing = TRUE;
if (m_nTextSelection) ClearSelection();
// CONSOLE_SCREEN_BUFFER_INFO csbi;
// ::GetConsoleScreenBufferInfo(m_hStdOutFresh, &csbi);
// in case buffer rows increased since last resize, and we're not using text buffer
if (!m_bUseTextBuffer) m_dwBufferRows = m_dwRows;
COORD coordBuffersSize;
coordBuffersSize.X = (SHORT)m_dwColumns;
coordBuffersSize.Y = (SHORT)m_dwBufferRows;
SMALL_RECT srConsoleRect;
srConsoleRect.Top = srConsoleRect.Left =0;
// srConsoleRect.Right = m_dwColumns - 1;
// srConsoleRect.Bottom= m_dwRows - 1;
#if 0
// order of setting window size and screen buffer size depends on current and desired dimensions
if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y > (DWORD) m_dwColumns * m_dwBufferRows) {
if (m_bUseTextBuffer && (csbi.dwSize.Y > m_dwBufferRows)) {
coordBuffersSize.Y = m_dwBufferRows = csbi.dwSize.Y;
}
::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect);
::SetConsoleScreenBufferSize(m_hStdOutFresh, coordBuffersSize);
// } else if (((DWORD)csbi.dwSize.X < m_dwColumns) || ((DWORD)csbi.dwSize.Y < m_dwBufferRows) || ((DWORD)(csbi.srWindow.Bottom - csbi.srWindow.Top + 1) != m_dwRows)) {
} else if ((DWORD) csbi.dwSize.X * csbi.dwSize.Y < (DWORD) m_dwColumns * m_dwBufferRows) {
if (csbi.dwSize.Y < m_dwBufferRows) {
m_dwBufferRows = coordBuffersSize.Y = csbi.dwSize.Y;
}
::SetConsoleScreenBufferSize(m_hStdOutFresh, coordBuffersSize);
::SetConsoleWindowInfo(m_hStdOutFresh, TRUE, &srConsoleRect);
}
#endif
SetScrollbarStuff();
CalcWindowSize();
SetWindowSizeAndPosition();
CreateOffscreenBuffers();
// if (m_bBitmapBackground) CreateBackgroundBitmap();
}
void Console::AllocateBuffer()
{
// resize screen buffer
delete[] m_pScreenBuffer;
m_pScreenBuffer = new CHAR_INFO[m_dwRows * m_dwColumns];
m_pScreenBufferNew = new CHAR_INFO[m_dwBufferRows * m_dwColumns];
::ZeroMemory( m_pScreenBufferNew, m_dwBufferRows * m_dwColumns * sizeof(CHAR_INFO));
m_bInitializing = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::RepaintWindow() {
RECT rect;
rect.top = 0;
rect.left = 0;
rect.bottom = m_nClientHeight;
rect.right = m_nClientWidth;
#if 0
if (m_bBitmapBackground) {
if (m_bRelativeBackground) {
::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, m_nX+m_nXBorderSize-m_nBackgroundOffsetX, m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY, SRCCOPY);
} else {
::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, 0, 0, SRCCOPY);
}
} else {
#endif
::FillRect(m_hdcConsole, &rect, m_hBkBrush);
// }
DWORD dwX = m_nInsideBorder;
DWORD dwY = m_nInsideBorder;
DWORD dwOffset = m_csbiConsole.srWindow.Top * m_dwColumns;
WORD attrBG;
// stuff used for caching
int nBkMode = TRANSPARENT;
COLORREF crBkColor = RGB(0, 0, 0);
COLORREF crTxtColor = RGB(0, 0, 0);
// int nNewBkMode = TRANSPARENT;
// COLORREF crNewBkColor = RGB(0, 0, 0);
// COLORREF crNewTxtColor = RGB(0, 0, 0);
bool bTextOut = false;
wstring strText(L"");
memcpy(m_pScreenBuffer, m_pScreenBufferNew + dwOffset, sizeof(CHAR_INFO)*m_dwRows * m_dwColumns);
dwOffset = 0;
if (m_nCharWidth > 0) {
// fixed pitch font
for (DWORD i = 0; i < m_dwRows; ++i) {
dwX = m_nInsideBorder;
dwY = i*m_nCharHeight + m_nInsideBorder;
nBkMode = TRANSPARENT;
crBkColor = RGB(0, 0, 0);
crTxtColor = RGB(0, 0, 0);
bTextOut = false;
attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4;
// here we decide how to paint text over the backgound
if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) {
::SetBkMode(m_hdcConsole, TRANSPARENT);
nBkMode = TRANSPARENT;
} else {
::SetBkMode(m_hdcConsole, OPAQUE);
nBkMode = OPAQUE;
::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]);
crBkColor = m_arrConsoleColors[attrBG];
}
::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]);
crTxtColor = m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF];
strText = m_pScreenBuffer[dwOffset].Char.UnicodeChar;
++dwOffset;
for (DWORD j = 1; j < m_dwColumns; ++j) {
attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4;
if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) {
if (nBkMode != TRANSPARENT) {
nBkMode = TRANSPARENT;
bTextOut = true;
}
} else {
if (nBkMode != OPAQUE) {
nBkMode = OPAQUE;
bTextOut = true;
}
if (crBkColor != m_arrConsoleColors[attrBG]) {
crBkColor = m_arrConsoleColors[attrBG];
bTextOut = true;
}
}
if (crTxtColor != (m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF])) {
crTxtColor = m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF];
bTextOut = true;
}
if (bTextOut) {
::TextOutW(m_hdcConsole, dwX, dwY, strText.c_str(), strText.length());
dwX += strText.length() * m_nCharWidth;
::SetBkMode(m_hdcConsole, nBkMode);
::SetBkColor(m_hdcConsole, crBkColor);
::SetTextColor(m_hdcConsole, crTxtColor);
strText = m_pScreenBuffer[dwOffset].Char.UnicodeChar;
} else {
strText += m_pScreenBuffer[dwOffset].Char.UnicodeChar;
}
++dwOffset;
}
if (strText.length() > 0) {
::TextOutW(m_hdcConsole, dwX, dwY, strText.c_str(), strText.length());
}
}
} else {
// variable pitch font
for (DWORD i = 0; i < m_dwRows; ++i) {
dwX = m_nInsideBorder;
dwY = i*m_nCharHeight + m_nInsideBorder;
for (DWORD j = 0; j < m_dwColumns; ++j) {
attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4;
// here we decide how to paint text over the backgound
if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) {
::SetBkMode(m_hdcConsole, TRANSPARENT);
} else {
::SetBkMode(m_hdcConsole, OPAQUE);
::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]);
}
::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]);
::TextOutW(m_hdcConsole, dwX, dwY, &(m_pScreenBuffer[dwOffset].Char.UnicodeChar), 1);
int nWidth;
::GetCharWidth32(m_hdcConsole, m_pScreenBuffer[dwOffset].Char.UnicodeChar, m_pScreenBuffer[dwOffset].Char.UnicodeChar, &nWidth);
dwX += nWidth;
++dwOffset;
}
}
}
if (m_pCursor) DrawCursor(TRUE);
::InvalidateRect(m_hWnd, NULL, FALSE);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::RepaintWindowChanges() {
DWORD dwX = m_nInsideBorder;
DWORD dwY = m_nInsideBorder;
DWORD dwDestOffset = 0;
DWORD dwSrcOffset = m_csbiConsole.srWindow.Top * m_dwColumns;
WORD attrBG;
if (m_nCharWidth > 0) {
// fixed pitch font
for (DWORD i = 0; i < m_dwRows; ++i) {
dwX = m_nInsideBorder;
dwY = i*m_nCharHeight + m_nInsideBorder;
for (DWORD j = 0; j < m_dwColumns; ++j) {
if (memcmp(&(m_pScreenBuffer[dwDestOffset]), &(m_pScreenBufferNew[dwSrcOffset]), sizeof(CHAR_INFO))) {
memcpy(&(m_pScreenBuffer[dwDestOffset]), &(m_pScreenBufferNew[dwSrcOffset]), sizeof(CHAR_INFO));
RECT rect;
rect.top = dwY;
rect.left = dwX;
rect.bottom = dwY + m_nCharHeight;
rect.right = dwX + m_nCharWidth;
#if 0
if (m_bBitmapBackground) {
if (m_bRelativeBackground) {
::BitBlt(m_hdcConsole, dwX, dwY, m_nCharWidth, m_nCharHeight, m_hdcBackground, m_nX+m_nXBorderSize-m_nBackgroundOffsetX+(int)dwX, m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY+(int)dwY, SRCCOPY);
} else {
::BitBlt(m_hdcConsole, dwX, dwY, m_nCharWidth, m_nCharHeight, m_hdcBackground, dwX, dwY, SRCCOPY);
}
} else {
#endif
::FillRect(m_hdcConsole, &rect, m_hBkBrush);
// }
attrBG = m_pScreenBuffer[dwDestOffset].Attributes >> 4;
// here we decide how to paint text over the backgound
if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) {
::SetBkMode(m_hdcConsole, TRANSPARENT);
} else {
::SetBkMode(m_hdcConsole, OPAQUE);
::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]);
}
::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwDestOffset].Attributes & 0xF]);
::TextOutW(m_hdcConsole, dwX, dwY, &(m_pScreenBuffer[dwDestOffset].Char.UnicodeChar), 1);
::InvalidateRect(m_hWnd, &rect, FALSE);
}
dwX += m_nCharWidth;
++dwDestOffset;
++dwSrcOffset;
}
}
} else {
// variable pitch font
if (memcmp(m_pScreenBuffer, m_pScreenBufferNew + dwDestOffset, sizeof(CHAR_INFO)*m_dwRows * m_dwColumns)) {
memcpy(m_pScreenBuffer, m_pScreenBufferNew + dwDestOffset, sizeof(CHAR_INFO)*m_dwRows * m_dwColumns);
RECT rect;
rect.top = 0;
rect.left = 0;
rect.bottom = m_nClientHeight;
rect.right = m_nClientWidth;
#if 0
if (m_bBitmapBackground) {
if (m_bRelativeBackground) {
::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, m_nX+m_nXBorderSize-m_nBackgroundOffsetX, m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY, SRCCOPY);
} else {
::BitBlt(m_hdcConsole, 0, 0, m_nClientWidth, m_nClientHeight, m_hdcBackground, 0, 0, SRCCOPY);
}
} else {
#endif
::FillRect(m_hdcConsole, &rect, m_hBkBrush);
// }
for (DWORD i = 0; i < m_dwRows; ++i) {
dwX = m_nInsideBorder;
dwY = i*m_nCharHeight + m_nInsideBorder;
for (DWORD j = 0; j < m_dwColumns; ++j) {
attrBG = m_pScreenBuffer[dwDestOffset].Attributes >> 4;
// here we decide how to paint text over the backgound
if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) {
::SetBkMode(m_hdcConsole, TRANSPARENT);
} else {
::SetBkMode(m_hdcConsole, OPAQUE);
::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]);
}
::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwDestOffset].Attributes & 0xF]);
::TextOutW(m_hdcConsole, dwX, dwY, &(m_pScreenBuffer[dwDestOffset].Char.UnicodeChar), 1);
int nWidth;
::GetCharWidth32(m_hdcConsole, m_pScreenBuffer[dwDestOffset].Char.UnicodeChar, m_pScreenBuffer[dwDestOffset].Char.UnicodeChar, &nWidth);
dwX += nWidth;
++dwDestOffset;
}
}
::InvalidateRect(m_hWnd, NULL, FALSE);
}
}
if (m_pCursor) DrawCursor();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::DrawCursor(BOOL bOnlyCursor) {
// first, erase old cursor image if needed
if (!bOnlyCursor && m_bCursorVisible) {
RECT rectCursorOld;
DrawCursorBackground(rectCursorOld);
::InvalidateRect(m_hWnd, &rectCursorOld, FALSE);
}
#if 0
// now, see if the cursor is visible...
CONSOLE_CURSOR_INFO cinf;
::GetConsoleCursorInfo(m_hStdOutFresh, &cinf);
m_bCursorVisible = cinf.bVisible;
#endif
// ... and draw it
if (m_bCursorVisible) {
#if 0
::GetConsoleScreenBufferInfo(m_hStdOutFresh, &m_csbiCursor);
if (m_csbiCursor.dwCursorPosition.Y < m_csbiCursor.srWindow.Top || m_csbiCursor.dwCursorPosition.Y > m_csbiCursor.srWindow.Bottom) {
m_bCursorVisible = FALSE;
return;
}
// set proper cursor offset
m_csbiCursor.dwCursorPosition.Y -= m_csbiCursor.srWindow.Top;
#endif
RECT rectCursor;
if (!bOnlyCursor) {
DrawCursorBackground(rectCursor);
} else {
GetCursorRect(rectCursor);
}
m_pCursor->Draw(&rectCursor);
::InvalidateRect(m_hWnd, &rectCursor, FALSE);
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
inline void Console::GetCursorRect(RECT& rectCursor) {
::ZeroMemory(&rectCursor, sizeof(RECT));
if (m_nCharWidth > 0) {
// fixed pitch
rectCursor.left = m_csbiCursor.dwCursorPosition.X * m_nCharWidth + m_nInsideBorder;
rectCursor.top = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight + m_nInsideBorder;
rectCursor.right = m_csbiCursor.dwCursorPosition.X * m_nCharWidth + m_nCharWidth + m_nInsideBorder;
rectCursor.bottom = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight + m_nCharHeight + m_nInsideBorder;
} else {
// variable pitch, we do a little joggling here :-)
RECT rectLine;
int nLastCharWidth;
auto_ptr<wchar_t> pszLine(new wchar_t[m_csbiCursor.dwCursorPosition.X + 2]);
::ZeroMemory(pszLine.get(), (m_csbiCursor.dwCursorPosition.X + 2)*sizeof(wchar_t));
for (short i = 0; i <= m_csbiCursor.dwCursorPosition.X; ++i) pszLine.get()[i] = m_pScreenBuffer[m_csbiCursor.dwCursorPosition.Y * m_dwColumns + i].Char.UnicodeChar;
rectLine.left = rectLine.right = 0;
rectLine.top = rectLine.bottom = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight;
::DrawTextW(
m_hdcConsole,
pszLine.get(),
-1,
&rectLine,
DT_CALCRECT);
if (!::GetCharWidth32(
m_hdcConsole,
pszLine.get()[m_csbiCursor.dwCursorPosition.X],
pszLine.get()[m_csbiCursor.dwCursorPosition.X],
&nLastCharWidth)) {
return;
}
rectCursor.left = rectLine.right - (DWORD)nLastCharWidth + m_nInsideBorder;
rectCursor.top = rectLine.top + m_nInsideBorder;
rectCursor.right = rectLine.right + m_nInsideBorder;
rectCursor.bottom = rectLine.bottom + m_nInsideBorder;
}
rectCursor.top -= m_csbiConsole.srWindow.Top * m_nCharHeight;
rectCursor.bottom -= m_csbiConsole.srWindow.Top * m_nCharHeight;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
inline void Console::DrawCursorBackground(RECT& rectCursor) {
GetCursorRect(rectCursor);
if (m_csbiCursor.dwCursorPosition.Y < m_csbiConsole.srWindow.Top ||
m_csbiCursor.dwCursorPosition.Y >= m_csbiConsole.srWindow.Top + (SHORT) m_dwRows) {
return;
}
DWORD dwOffset = (m_csbiCursor.dwCursorPosition.Y-m_csbiConsole.srWindow.Top)*m_dwColumns + m_csbiCursor.dwCursorPosition.X;
WORD attrBG = m_pScreenBuffer[dwOffset].Attributes >> 4;
// here we decide how to paint text over the backgound
if (m_arrConsoleColors[attrBG] == m_crConsoleBackground) {
::SetBkMode(m_hdcConsole, TRANSPARENT);
} else {
::SetBkMode(m_hdcConsole, OPAQUE);
::SetBkColor(m_hdcConsole, m_arrConsoleColors[attrBG]);
}
::SetTextColor(m_hdcConsole, m_bUseFontColor ? m_crFontColor : m_arrConsoleColors[m_pScreenBuffer[dwOffset].Attributes & 0xF]);
#if 0
if (m_bBitmapBackground) {
if (m_bRelativeBackground) {
::BitBlt(
m_hdcConsole,
rectCursor.left,
rectCursor.top,
rectCursor.right - rectCursor.left,
rectCursor.bottom - rectCursor.top,
m_hdcBackground,
m_nX+m_nXBorderSize-m_nBackgroundOffsetX + rectCursor.left,
m_nY+m_nCaptionSize+m_nYBorderSize-m_nBackgroundOffsetY + rectCursor.top,
SRCCOPY);
} else {
::BitBlt(
m_hdcConsole,
rectCursor.left,
rectCursor.top,
rectCursor.right - rectCursor.left,
rectCursor.bottom - rectCursor.top,
m_hdcBackground,
rectCursor.left,
rectCursor.top, SRCCOPY);
}
} else {
#endif
::FillRect(m_hdcConsole, &rectCursor, m_hBkBrush);
// }
::TextOutW(
m_hdcConsole,
rectCursor.left,
rectCursor.top,
&(m_pScreenBuffer[dwOffset].Char.UnicodeChar),
1);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::ClearSelection() {
m_nTextSelection = TEXT_SELECTION_NONE;
m_coordSelOrigin.X = 0;
m_coordSelOrigin.Y = 0;
::ZeroMemory(&m_rectSelection, sizeof(RECT));
RepaintWindow();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
DWORD Console::GetChangeRate() {
DWORD dwCount = m_dwRows * m_dwColumns;
DWORD dwChangedPositions = 0;
for (DWORD i = 0; i < dwCount; ++i) {
if (m_pScreenBuffer[i].Char.UnicodeChar != m_pScreenBufferNew[i].Char.UnicodeChar) ++dwChangedPositions;
}
return dwChangedPositions*100/dwCount;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::ShowHideWindow() {
::ShowWindowAsync(m_hWnd, m_bHideWindow ? SW_HIDE : SW_SHOW);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::ShowHideConsole() {
::ShowWindow(m_hWndConsole, m_bHideConsole ? SW_HIDE : SW_SHOWNORMAL);
if (!m_bHideConsole) ::SetForegroundWindow(m_hWndConsole);
UpdateHideConsoleMenuItem();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#if 0
void Console::ShowHideConsoleTimeout() {
::KillTimer(m_hWnd, TIMER_SHOW_HIDE_CONSOLE);
ShowHideConsole();
}
#endif
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::ToggleWindowOnTop() {
if (m_dwCurrentZOrder == m_dwOriginalZOrder) {
m_dwCurrentZOrder = Z_ORDER_ONTOP;
} else {
m_dwCurrentZOrder = m_dwOriginalZOrder;
}
HWND hwndZ = 0;
switch (m_dwCurrentZOrder) {
case Z_ORDER_REGULAR : hwndZ = HWND_NOTOPMOST; break;
case Z_ORDER_ONTOP : hwndZ = HWND_TOPMOST; break;
case Z_ORDER_ONBOTTOM : hwndZ = HWND_BOTTOM; break;
default : return;
}
::SetWindowPos(
m_hWnd,
hwndZ,
0,
0,
0,
0,
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
UpdateOnTopMenuItem();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL Console::HandleMenuCommand(DWORD dwID) {
// check if it's one of the main menu commands
switch (dwID) {
/*
case ID_SHOW_README_FILE:
ShowReadmeFile();
return FALSE;
case ID_ABOUT:
About();
return FALSE;
*/
case ID_COPY:
CopyTextToClipboard();
return FALSE;
case ID_PASTE:
PasteClipoardText();
return FALSE;
#if 0
case ID_HIDE_CONSOLE:
m_bHideConsole = !m_bHideConsole;
ShowHideConsole();
return FALSE;
case ID_EDIT_CONFIG_FILE:
EditConfigFile();
return FALSE;
case ID_RELOAD_SETTINGS:
ReloadSettings();
return FALSE;
case ID_TOGGLE_ONTOP:
ToggleWindowOnTop();
return FALSE;
#endif
case ID_EXIT_CONSOLE:
::SendMessage(m_hWnd, WM_CLOSE, 0, 0);
return FALSE;
case SC_MINIMIZE:
if (m_dwTaskbarButton > TASKBAR_BUTTON_NORMAL) {
m_bHideWindow = !m_bHideWindow;
ShowHideWindow();
::SetForegroundWindow(m_hWnd);
return FALSE;
}
return TRUE;
}
#if 0
// check if it's one of config file submenu items
if ((dwID >= ID_FIRST_XML_FILE) &&
(dwID <= ID_LAST_XML_FILE)) {
TCHAR szFilename[MAX_PATH];
::ZeroMemory(szFilename, sizeof(szFilename));
::GetMenuString(m_hConfigFilesMenu, dwID, szFilename, MAX_PATH, MF_BYCOMMAND);
m_strConfigFile = tstring(szFilename);
if (m_dwReloadNewConfig == RELOAD_NEW_CONFIG_PROMPT) {
if (::MessageBox(
m_hWndConsole,
_T("Load new settings?"),
_T("New configuration selected"),
MB_YESNO|MB_ICONQUESTION) == IDYES) {
ReloadSettings();
}
} else if (m_dwReloadNewConfig == RELOAD_NEW_CONFIG_YES) {
ReloadSettings();
}
return FALSE;
}
#endif
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::UpdateOnTopMenuItem() {
#if 0
::CheckMenuItem(::GetSubMenu(m_hPopupMenu, 0), ID_TOGGLE_ONTOP, MF_BYCOMMAND | ((m_dwCurrentZOrder == Z_ORDER_ONTOP) ? MF_CHECKED : MF_UNCHECKED));
::CheckMenuItem(m_hSysMenu, ID_TOGGLE_ONTOP, MF_BYCOMMAND | ((m_dwCurrentZOrder == Z_ORDER_ONTOP) ? MF_CHECKED : MF_UNCHECKED));
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::UpdateHideConsoleMenuItem() {
#if 0
::CheckMenuItem(::GetSubMenu(m_hPopupMenu, 0), ID_HIDE_CONSOLE, MF_BYCOMMAND | (m_bHideConsole ? MF_CHECKED : MF_UNCHECKED));
::CheckMenuItem(m_hSysMenu, ID_HIDE_CONSOLE, MF_BYCOMMAND | (m_bHideConsole ? MF_CHECKED : MF_UNCHECKED));
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::UpdateConfigFilesSubmenu() {
#if 0
// populate m_hConfigFilesMenu
// first, delete old items
while (::GetMenuItemCount(m_hConfigFilesMenu) != 0) ::DeleteMenu(m_hConfigFilesMenu, 0, MF_BYPOSITION);
// then, enumerate the files
WIN32_FIND_DATA wfd;
HANDLE hWfd = NULL;
BOOL bMoreFiles = TRUE;
DWORD dwID = ID_FIRST_XML_FILE;
::ZeroMemory(&wfd, sizeof(WIN32_FIND_DATA));
// create the search mask...
int nBackslashPos = m_strConfigFile.rfind(_TCHAR('\\'));
tstring strConfigFileDir(m_strConfigFile.substr(0, nBackslashPos+1));
tstring strSearchFileMask(strConfigFileDir + tstring(_T("*.xml")));
// ... and enumearate files
hWfd = ::FindFirstFile(strSearchFileMask.c_str(), &wfd);
while ((hWfd != INVALID_HANDLE_VALUE) && bMoreFiles) {
MENUITEMINFO mii;
TCHAR szFilename[MAX_PATH];
_sntprintf(szFilename, MAX_PATH, _T("%s"), (strConfigFileDir + tstring(wfd.cFileName)).c_str());
::ZeroMemory(&mii, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
mii.fType = MFT_RADIOCHECK | MFT_STRING;
mii.wID = dwID++;
mii.dwTypeData = szFilename;
mii.cch = _tcslen(wfd.cFileName);
if (_tcsicmp(szFilename, m_strConfigFile.c_str()) == 0) {
mii.fState = MFS_CHECKED;
} else {
mii.fState = MFS_UNCHECKED;
}
::InsertMenuItem(m_hConfigFilesMenu, dwID-ID_FIRST_XML_FILE, TRUE, &mii);
bMoreFiles = ::FindNextFile(hWfd, &wfd);
}
::FindClose(hWfd);
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::CopyTextToClipboard() {
int nSelX = (m_rectSelection.left - m_nInsideBorder)/m_nCharWidth;
int nSelY = (m_rectSelection.top - m_nInsideBorder)/m_nCharHeight;
int nSelColumns = (m_rectSelection.right-m_rectSelection.left)/m_nCharWidth;
int nSelRows = (m_rectSelection.bottom-m_rectSelection.top)/m_nCharHeight;
// nothing selected, just return
if ((nSelColumns == 0) || (nSelRows == 0)) {
ClearSelection();
return;
}
if (!::OpenClipboard(m_hWnd)) {
ClearSelection();
return;
}
::EmptyClipboard();
HGLOBAL hglbData = ::GlobalAlloc(GMEM_MOVEABLE, (nSelColumns+2)*nSelRows*sizeof(TCHAR));
if (hglbData == NULL) {
::CloseClipboard();
ClearSelection();
return;
}
// lock the handle and copy the text to the buffer.
wchar_t* pszData = (wchar_t*)::GlobalLock(hglbData);
{
int i;
for (i = 0; i < nSelRows; ++i) {
for (int j = 0; j < nSelColumns; ++j) {
pszData[i*(nSelColumns+2) + j] = m_pScreenBuffer[(nSelY+i)*m_dwColumns + nSelX + j].Char.UnicodeChar;
}
// at the end of each row we put \r\n (except for the last one where we put \0)
pszData[i*(nSelColumns+2) + nSelColumns] = _TCHAR('\r');
pszData[i*(nSelColumns+2) + nSelColumns + 1] = _TCHAR('\n');
}
pszData[(i-1)*(nSelColumns+2) + nSelColumns] = _TCHAR('\x0');
}
::GlobalUnlock(hglbData);
if (::SetClipboardData(CF_UNICODETEXT, hglbData) == NULL) {
// we need to global-free data only if copying failed
}
::CloseClipboard();
// !!! No call to GlobalFree here. Next app that uses clipboard will call EmptyClipboard to free the data
ClearSelection();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::PasteClipoardText() {
if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return;
if (::OpenClipboard(m_hWnd)) {
HANDLE hData = ::GetClipboardData(CF_UNICODETEXT);
SendTextToConsole((wchar_t*)::GlobalLock(hData));
::GlobalUnlock(hData);
::CloseClipboard();
}
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::ShowReadmeFile() {
// prepare editor parameters
tstring strParams(m_strConfigEditorParams);
if (strParams.length() == 0) {
// no params, just use the readme file
strParams = m_strReadmeFile;
} else {
tstring::size_type nPos = strParams.find(_T("%f"));
if (nPos == tstring::npos) {
// no '%f' in editor params, concatenate readme file name
strParams += _T(" ");
strParams += m_strReadmeFile;
} else {
// replace '%f' with readme file name
strParams = strParams.replace(nPos, 2, m_strReadmeFile);
}
}
::ShellExecute(NULL, NULL, m_strConfigEditor.c_str(), strParams.c_str(), NULL, SW_SHOWNORMAL);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// About - shows an about dialog
void Console::About()
{
CAboutDlg dlg(m_hWnd);
dlg.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::SendTextToConsole(const wchar_t *pszText)
{
if (!pszText || (wcslen(pszText) == 0)) return;
BOOL c_state = FALSE;
if (m_pCursor)
{
c_state = (m_pCursor != NULL && m_pCursor->GetState());
m_pCursor->SetState(FALSE);
DrawCursor();
}
int idx = m_csbiCursor.dwCursorPosition.X + m_csbiCursor.dwCursorPosition.Y * m_dwColumns;
RECT rectInval;
int cursorX;
int cursorY;
WORD attr = (WORD)(m_nTextColor + (m_nTextBgColor << 4));
cursorX = m_csbiCursor.dwCursorPosition.X * m_nCharWidth + m_nInsideBorder;
cursorY = m_csbiCursor.dwCursorPosition.Y * m_nCharHeight + m_nInsideBorder;
rectInval.left = cursorX;
rectInval.top = cursorY;
rectInval.right = cursorX;
rectInval.bottom = cursorY + m_nCharHeight;
for (; *pszText; pszText++) {
int charWidth;
::GetCharWidth32( m_hdcConsole, *pszText, *pszText, &charWidth);
if (cursorX + m_nCharWidth > rectInval.right) {
rectInval.right = cursorX + m_nCharWidth;
}
if (cursorX < rectInval.left) {
rectInval.left = cursorX;
}
if (cursorY + m_nCharHeight > rectInval.bottom) {
rectInval.bottom = cursorY + m_nCharHeight;
}
if (cursorY < rectInval.top) {
rectInval.top = cursorY;
}
if (*pszText == 8) {
if (m_csbiCursor.dwCursorPosition.X) {
m_csbiCursor.dwCursorPosition.X--;
cursorX -= m_nCharWidth;
idx--;
} else if (m_csbiCursor.dwCursorPosition.Y) {
if (m_csbiCursor.dwCursorPosition.Y == m_csbiConsole.srWindow.Top) {
OnVScroll( SB_LINEUP);
}
m_csbiCursor.dwCursorPosition.Y--;
m_csbiCursor.dwCursorPosition.X = (SHORT)m_dwColumns - 1;
cursorX = m_nCharWidth * m_csbiCursor.dwCursorPosition.X;
idx--;
}
} else if (*pszText != '\n' &&
*pszText != '\r') {
m_pScreenBufferNew[ idx].Attributes = attr;
m_pScreenBufferNew[ idx].Char.UnicodeChar = *pszText;
idx++;
cursorX += m_nCharWidth;
m_csbiCursor.dwCursorPosition.X++;
}
if (m_csbiCursor.dwCursorPosition.X >= (SHORT) m_dwColumns || *pszText == '\r' || *pszText == '\n' ) {
m_csbiCursor.dwCursorPosition.X = 0;
cursorX = m_nInsideBorder;
if (*pszText != '\r') {
m_csbiCursor.dwCursorPosition.Y++;
if (m_csbiCursor.dwCursorPosition.Y >= (SHORT)m_dwBufferRows) {
m_csbiCursor.dwCursorPosition.Y--;
idx = m_csbiCursor.dwCursorPosition.X + m_csbiCursor.dwCursorPosition.Y * m_dwColumns;
::CopyMemory( m_pScreenBufferNew, m_pScreenBufferNew + m_dwColumns, idx * sizeof( CHAR_INFO));
::ZeroMemory( m_pScreenBufferNew + idx, m_dwColumns * sizeof( CHAR_INFO));
} else if (m_csbiCursor.dwCursorPosition.Y == m_csbiConsole.srWindow.Top + (SHORT)m_dwRows) {
OnVScroll( SB_LINEDOWN);
} else {
cursorY += m_nCharHeight;
}
}
idx = m_csbiCursor.dwCursorPosition.X + m_csbiCursor.dwCursorPosition.Y * m_dwColumns;
}
}
::InvalidateRect( m_hWnd, &rectInval, TRUE);
::SetTimer(m_hWnd, TIMER_REPAINT_CHANGE, m_dwChangeRepaintInt, NULL);
if (m_pCursor)
{
m_pCursor->SetState(c_state);
}
#if 0
HANDLE hStdIn = ::CreateFile(_T("CONIN$"), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
DWORD dwTextLen = _tcslen(pszText);
DWORD dwTextWritten = 0;
INPUT_RECORD* pKeyEvents = new INPUT_RECORD[dwTextLen];
::ZeroMemory(pKeyEvents, sizeof(INPUT_RECORD)*dwTextLen);
for (DWORD i = 0; i < dwTextLen; ++i) {
pKeyEvents[i].EventType = KEY_EVENT;
pKeyEvents[i].Event.KeyEvent.bKeyDown = TRUE;
pKeyEvents[i].Event.KeyEvent.wRepeatCount = 1;
pKeyEvents[i].Event.KeyEvent.wVirtualKeyCode = 0;
pKeyEvents[i].Event.KeyEvent.wVirtualScanCode = 0;
pKeyEvents[i].Event.KeyEvent.uChar.UnicodeChar = pszText[i];
pKeyEvents[i].Event.KeyEvent.dwControlKeyState = 0;
}
::WriteConsoleInput(hStdIn, pKeyEvents, dwTextLen, &dwTextWritten);
DEL_ARR(pKeyEvents);
::CloseHandle(hStdIn);
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
tstring Console::GetFullFilename(const tstring& strFilename) {
TCHAR szFilePath[MAX_PATH];
TCHAR* pszFilename;
::ZeroMemory(szFilePath, sizeof(szFilePath));
::GetFullPathName(strFilename.c_str(), MAX_PATH, szFilePath, &pszFilename);
return tstring(szFilePath);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::GetDesktopRect(RECT& rectDesktop) {
// if (g_bWin2000) {
POINT pt;
if (::GetCursorPos(&pt)) {
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST), &monitorInfo)) {
rectDesktop = monitorInfo.rcWork;
}
} else {
rectDesktop.left = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
rectDesktop.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
rectDesktop.right = rectDesktop.left + ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
rectDesktop.bottom = rectDesktop.top + ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
#if 0
} else {
// we keep this for WinNT compatibility
rectDesktop.left= 0;
rectDesktop.top = 0;
rectDesktop.right = ::GetSystemMetrics(SM_CXSCREEN);
rectDesktop.bottom = ::GetSystemMetrics(SM_CYSCREEN);
RECT rectTaskbar = {0, 0, 0, 0};
HWND hWndTaskbar = ::FindWindow(_T("Shell_TrayWnd"), _T(""));
if (hWndTaskbar) {
::GetWindowRect(hWndTaskbar, &rectTaskbar);
if ((rectTaskbar.top <= rectDesktop.top) && (rectTaskbar.left <= rectDesktop.left) && (rectTaskbar.right >= rectDesktop.right)) {
// top taskbar
rectDesktop.top += rectTaskbar.bottom;
} else if ((rectTaskbar.top > rectDesktop.top) && (rectTaskbar.left <= rectDesktop.left)) {
// bottom taskbar
rectDesktop.bottom = rectTaskbar.top;
} else if ((rectTaskbar.top <= rectDesktop.top) && (rectTaskbar.left > rectDesktop.left)) {
// right taskbar
rectDesktop.right = rectTaskbar.left;
} else {
// left taskbar
rectDesktop.left += rectTaskbar.right;
}
}
}
#endif
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK Console::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
Console *myself = (Console*) ::GetWindowLongPtr( hwnd, GWLP_USERDATA );
switch (uMsg) {
case WM_CREATE:
return 0;
case WM_PAINT:
// paint the window
myself->OnPaint();
return 0;
case WM_ERASEBKGND:
return -1;
case WM_SIZE:
// set the size and position of the window
return 0;
case WM_CLOSE:
// ::DestroyWindow(myself->m_hWnd);
// Probably want to just hide the window if the X is hit. That way it can continue
// to update on script output
ShowWindow( hwnd, FALSE);
return 0;
case WM_DESTROY:
myself->OnDestroy();
return 0;
case WM_NCDESTROY:
myself->OnNcDestroy();
return 0;
case WM_LBUTTONDOWN:
myself->OnLButtonDown((UINT)wParam, MAKEPOINTS(lParam));
return 0;
case WM_LBUTTONUP:
myself->OnLButtonUp((UINT)wParam, MAKEPOINTS(lParam));
return 0;
case WM_LBUTTONDBLCLK:
myself->OnLButtonDblClick((UINT)wParam, MAKEPOINTS(lParam));
return 0;
case WM_RBUTTONUP:
myself->OnRButtonUp((UINT)wParam, MAKEPOINTS(lParam));
return 0;
case WM_MBUTTONDOWN:
myself->OnMButtonDown((UINT)wParam, MAKEPOINTS(lParam));
return 0;
case WM_MOUSEMOVE:
myself->OnMouseMove((UINT)wParam, MAKEPOINTS(lParam));
return 0;
case WM_SETCURSOR:
myself->OnSetCursor(LOWORD(lParam), HIWORD(lParam));
::DefWindowProc(myself->m_hWnd, uMsg, wParam, lParam);
return 0;
case WM_INITMENUPOPUP:
myself->OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), (BOOL)HIWORD(lParam));
return 0;
case WM_DROPFILES:
myself->OnDropFiles((HDROP)wParam);
return 0;
case WM_WINDOWPOSCHANGING:
myself->OnWindowPosChanging((LPWINDOWPOS)lParam);
return 0;
case WM_ACTIVATEAPP:
myself->OnActivateApp((BOOL)wParam, (DWORD)lParam);
return 0;
#if 0
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
MSG msg;
::ZeroMemory(&msg, sizeof(MSG));
msg.hwnd = myself->m_hWnd;
msg.message = uMsg;
msg.wParam = wParam;
msg.lParam = lParam;
::TranslateMessage(&msg);
::PostMessage(myself->m_hWndConsole, uMsg, wParam, lParam);
return 0;
#endif
case WM_CHAR:
myself->OnChar( (WORD) wParam);
break;
case WM_KEYDOWN:
case WM_KEYUP:
// case WM_MOUSEWHEEL:
// ::PostMessage(myself->m_hWndConsole, uMsg, wParam, lParam);
return 0;
case WM_VSCROLL:
myself->OnVScroll(wParam);
return 0;
case WM_TIMER:
switch (wParam) {
case TIMER_REPAINT_CHANGE:
case TIMER_REPAINT_MASTER:
myself->OnPaintTimer();
return 0;
case CURSOR_TIMER:
myself->OnCursorTimer();
return 0;
#if 0
case TIMER_SHOW_HIDE_CONSOLE:
myself->ShowHideConsoleTimeout();
return 0;
#endif
default:
return 1;
}
case WM_COMMAND:
if (myself->OnCommand(wParam, lParam)) {
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
} else {
return 0;
}
case WM_SYSCOMMAND:
if (myself->OnSysCommand(wParam, lParam)) {
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
} else {
return 0;
}
case WM_TRAY_NOTIFY:
myself->OnTrayNotify(wParam, lParam);
return 0;
// case WM_SETTINGCHANGE:
//
// myself->OnWallpaperChanged((TCHAR*)lParam);
// return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
case WM_INPUTLANGCHANGEREQUEST:
myself->OnInputLangChangeRequest(wParam, lParam);
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
// process other messages
default:
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// MonitorThread - shell activities monitor
DWORD WINAPI Console::MonitorThreadStatic(LPVOID lpParam) {
return ((Console*)lpParam)->MonitorThread();
}
DWORD Console::MonitorThread() {
// HANDLE arrHandles[] = {m_hConsoleProcess, m_hQuitEvent, m_hStdOut};
// HANDLE arrHandles[] = { m_hStdOut};
for (;;) { // Infinite loop
#if 0
DWORD dwWait = ::WaitForMultipleObjects(1, arrHandles, FALSE, INFINITE);
if (dwWait == WAIT_OBJECT_0) {
::PostMessage(m_hWnd, WM_CLOSE, 0, 0);
break;
} else if (dwWait == WAIT_OBJECT_0 + 1) {
break;
} else if (dwWait == WAIT_OBJECT_0 + 2) {
#endif
AddOutput();
::SetTimer(m_hWnd, TIMER_REPAINT_CHANGE, m_dwChangeRepaintInt, NULL);
// we sleep here for a while, to prevent 'flooding' of m_hStdOut events
::Sleep(m_dwChangeRepaintInt);
::ResetEvent(m_hStdOut);
// }
}
// return 0;
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void Console::AddOutput() {
DWORD bytesRead;
char buf[801];
wchar_t wbuf[801];
::ReadFile( m_hStdOut, buf, sizeof(buf)/sizeof(wchar_t)-1, &bytesRead, NULL);
if (bytesRead == 0) {
return;
}
buf[bytesRead] = 0;
MultiByteToWideChar( CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(wbuf[0]));
SendTextToConsole( wbuf);
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
BOOL WINAPI Console::CtrlHandler(DWORD dwCtrlType) {
if ((dwCtrlType == CTRL_C_EVENT) || (dwCtrlType == CTRL_BREAK_EVENT)) {
return TRUE;
} else {
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////