guiconsole.c

来自「一个类似windows」· C语言 代码 · 共 1,107 行 · 第 1/3 页

C
1,107
字号
/* $Id: guiconsole.c 21263 2006-03-08 23:32:01Z audit $
 *
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS system libraries
 * FILE:            subsys/csrss/win32csr/guiconsole.c
 * PURPOSE:         Implementation of gui-mode consoles
 */

/* INCLUDES ******************************************************************/

#include "w32csr.h"

#define NDEBUG
#include <debug.h>

/* Not defined in any header file */
extern VOID STDCALL PrivateCsrssManualGuiCheck(LONG Check);

/* GLOBALS *******************************************************************/

typedef struct GUI_CONSOLE_DATA_TAG
{
  HFONT Font;
  unsigned CharWidth;
  unsigned CharHeight;
  PWCHAR LineBuffer;
  BOOL CursorBlinkOn;
  BOOL ForceCursorOff;
  CRITICAL_SECTION Lock;
  RECT Selection;
  POINT SelectionStart;
  BOOL MouseDown;
} GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;

#ifndef WM_APP
#define WM_APP 0x8000
#endif
#define PM_CREATE_CONSOLE  (WM_APP + 1)
#define PM_DESTROY_CONSOLE (WM_APP + 2)

#define CURSOR_BLINK_TIME 500

static BOOL ConsInitialized = FALSE;
static HWND NotifyWnd;

/* FUNCTIONS *****************************************************************/

static VOID FASTCALL
GuiConsoleGetDataPointers(HWND hWnd, PCSRSS_CONSOLE *Console, PGUI_CONSOLE_DATA *GuiData)
{
  *Console = (PCSRSS_CONSOLE) GetWindowLongPtrW(hWnd, GWL_USERDATA);
  *GuiData = (NULL == *Console ? NULL : (*Console)->PrivateData);
}

static BOOL FASTCALL
GuiConsoleHandleNcCreate(HWND hWnd, CREATESTRUCTW *Create)
{
  RECT Rect;
  PCSRSS_CONSOLE Console = (PCSRSS_CONSOLE) Create->lpCreateParams;
  PGUI_CONSOLE_DATA GuiData;
  HDC Dc;
  HFONT OldFont;
  TEXTMETRICW Metrics;

  GuiData = HeapAlloc(Win32CsrApiHeap, HEAP_ZERO_MEMORY,
                      sizeof(GUI_CONSOLE_DATA) +
                      (Console->Size.X + 1) * sizeof(WCHAR));
  if (NULL == GuiData)
    {
      DPRINT1("GuiConsoleNcCreate: HeapAlloc failed\n");
      return FALSE;
    }

  InitializeCriticalSection(&GuiData->Lock);

  GuiData->LineBuffer = (PWCHAR)(GuiData + 1);

  GuiData->Font = CreateFontW(12, 0, 0, TA_BASELINE, FW_NORMAL,
                              FALSE, FALSE, FALSE, OEM_CHARSET,
                              OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                              NONANTIALIASED_QUALITY, FIXED_PITCH | FF_DONTCARE,
                              L"Bitstream Vera Sans Mono");
  if (NULL == GuiData->Font)
    {
      DPRINT1("GuiConsoleNcCreate: CreateFont failed\n");
      DeleteCriticalSection(&GuiData->Lock);
      HeapFree(Win32CsrApiHeap, 0, GuiData);
      return FALSE;
    }
  Dc = GetDC(hWnd);
  if (NULL == Dc)
    {
      DPRINT1("GuiConsoleNcCreate: GetDC failed\n");
      DeleteObject(GuiData->Font);
      DeleteCriticalSection(&GuiData->Lock);
      HeapFree(Win32CsrApiHeap, 0, GuiData);
      return FALSE;
    }
  OldFont = SelectObject(Dc, GuiData->Font);
  if (NULL == OldFont)
    {
      DPRINT1("GuiConsoleNcCreate: SelectObject failed\n");
      ReleaseDC(hWnd, Dc);
      DeleteObject(GuiData->Font);
      DeleteCriticalSection(&GuiData->Lock);
      HeapFree(Win32CsrApiHeap, 0, GuiData);
      return FALSE;
    }
  if (! GetTextMetricsW(Dc, &Metrics))
    {
      DPRINT1("GuiConsoleNcCreate: GetTextMetrics failed\n");
      SelectObject(Dc, OldFont);
      ReleaseDC(hWnd, Dc);
      DeleteObject(GuiData->Font);
      DeleteCriticalSection(&GuiData->Lock);
      HeapFree(Win32CsrApiHeap, 0, GuiData);
      return FALSE;
    }
  GuiData->CharWidth = Metrics.tmMaxCharWidth;
  GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
  SelectObject(Dc, OldFont);

  ReleaseDC(hWnd, Dc);
  GuiData->CursorBlinkOn = TRUE;
  GuiData->ForceCursorOff = FALSE;

  GuiData->Selection.left = -1;

  Console->PrivateData = GuiData;
  SetWindowLongPtrW(hWnd, GWL_USERDATA, (DWORD_PTR) Console);

  GetWindowRect(hWnd, &Rect);
  Rect.right = Rect.left + Console->Size.X * GuiData->CharWidth +
               2 * GetSystemMetrics(SM_CXFIXEDFRAME);
  Rect.bottom = Rect.top + Console->Size.Y * GuiData->CharHeight +
               2 * GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION);
  MoveWindow(hWnd, Rect.left, Rect.top, Rect.right - Rect.left,
             Rect.bottom - Rect.top, FALSE);

  SetTimer(hWnd, 1, CURSOR_BLINK_TIME, NULL);

  return (BOOL) DefWindowProcW(hWnd, WM_NCCREATE, 0, (LPARAM) Create);
}

static COLORREF FASTCALL
GuiConsoleRGBFromAttribute(BYTE Attribute)
{
  int Red = (Attribute & 0x04 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
  int Green = (Attribute & 0x02 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);
  int Blue = (Attribute & 0x01 ? (Attribute & 0x08 ? 0xff : 0x80) : 0x00);

  return RGB(Red, Green, Blue);
}

static VOID FASTCALL
GuiConsoleSetTextColors(HDC Dc, BYTE Attribute)
{
  SetTextColor(Dc, GuiConsoleRGBFromAttribute(Attribute & 0x0f));
  SetBkColor(Dc, GuiConsoleRGBFromAttribute((Attribute & 0xf0) >> 4));
}

static VOID FASTCALL
GuiConsoleGetLogicalCursorPos(PCSRSS_SCREEN_BUFFER Buff, ULONG *CursorX, ULONG *CursorY)
{
  *CursorX = Buff->CurrentX;
  if (Buff->CurrentY < Buff->ShowY)
    {
      *CursorY = Buff->MaxY - Buff->ShowY + Buff->CurrentY;
    }
  else
    {
      *CursorY = Buff->CurrentY - Buff->ShowY;
    }
}


static VOID FASTCALL
GuiConsoleUpdateSelection(HWND hWnd, PRECT rc, PGUI_CONSOLE_DATA GuiData)
{
  RECT oldRect = GuiData->Selection;

  if(rc != NULL)
  {
    RECT changeRect = *rc;

    GuiData->Selection = *rc;

    changeRect.left *= GuiData->CharWidth;
    changeRect.top *= GuiData->CharHeight;
    changeRect.right *= GuiData->CharWidth;
    changeRect.bottom *= GuiData->CharHeight;

    if(rc->left != oldRect.left ||
       rc->top != oldRect.top ||
       rc->right != oldRect.right ||
       rc->bottom != oldRect.bottom)
    {
      if(oldRect.left != -1)
      {
        HRGN rgn1, rgn2;

        oldRect.left *= GuiData->CharWidth;
        oldRect.top *= GuiData->CharHeight;
        oldRect.right *= GuiData->CharWidth;
        oldRect.bottom *= GuiData->CharHeight;

        /* calculate the region that needs to be updated */
        if((rgn1 = CreateRectRgnIndirect(&oldRect)))
        {
          if((rgn2 = CreateRectRgnIndirect(&changeRect)))
          {
            if(CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
            {
              InvalidateRgn(hWnd, rgn1, FALSE);
            }

            DeleteObject(rgn2);
          }
          DeleteObject(rgn1);
        }
      }
      else
      {
        InvalidateRect(hWnd, &changeRect, FALSE);
      }
    }
  }
  else if(oldRect.left != -1)
  {
    /* clear the selection */
    GuiData->Selection.left = -1;
    oldRect.left *= GuiData->CharWidth;
    oldRect.top *= GuiData->CharHeight;
    oldRect.right *= GuiData->CharWidth;
    oldRect.bottom *= GuiData->CharHeight;
    InvalidateRect(hWnd, &oldRect, FALSE);
  }
}


static VOID FASTCALL
GuiConsolePaint(PCSRSS_CONSOLE Console,
                PGUI_CONSOLE_DATA GuiData,
                HDC hDC,
                PRECT rc)
{
    PCSRSS_SCREEN_BUFFER Buff;
    ULONG TopLine, BottomLine, LeftChar, RightChar;
    ULONG Line, Char, Start;
    PBYTE From;
    PWCHAR To;
    BYTE LastAttribute, Attribute;
    ULONG CursorX, CursorY, CursorHeight;
    HBRUSH CursorBrush, OldBrush;
    HFONT OldFont;

    Buff = Console->ActiveBuffer;

    TopLine = rc->top / GuiData->CharHeight;
    BottomLine = (rc->bottom + (GuiData->CharHeight - 1)) / GuiData->CharHeight - 1;
    LeftChar = rc->left / GuiData->CharWidth;
    RightChar = (rc->right + (GuiData->CharWidth - 1)) / GuiData->CharWidth - 1;
    LastAttribute = Buff->Buffer[(TopLine * Buff->MaxX + LeftChar) * 2 + 1];

    GuiConsoleSetTextColors(hDC,
                            LastAttribute);

    EnterCriticalSection(&Buff->Header.Lock);

    OldFont = SelectObject(hDC,
                           GuiData->Font);

    for (Line = TopLine; Line <= BottomLine; Line++)
    {
        if (Line + Buff->ShowY < Buff->MaxY)
        {
            From = Buff->Buffer + ((Line + Buff->ShowY) * Buff->MaxX + LeftChar) * 2;
        }
        else
        {
            From = Buff->Buffer +
                   ((Line - (Buff->MaxY - Buff->ShowY)) * Buff->MaxX + LeftChar) * 2;
        }
        Start = LeftChar;
        To = GuiData->LineBuffer;

        for (Char = LeftChar; Char <= RightChar; Char++)
        {
            if (*(From + 1) != LastAttribute)
            {
                TextOutW(hDC,
                         Start * GuiData->CharWidth,
                         Line * GuiData->CharHeight,
                         GuiData->LineBuffer,
                         Char - Start);
                Start = Char;
                To = GuiData->LineBuffer;
                Attribute = *(From + 1);
                if (Attribute != LastAttribute)
                {
                    GuiConsoleSetTextColors(hDC,
                                            Attribute);
                    LastAttribute = Attribute;
                }
            }

            MultiByteToWideChar(Console->OutputCodePage,
                                0,
                                (PCHAR)From,
                                1,
                                To,
                                1);
            To++;
            From += 2;
        }

        TextOutW(hDC,
                 Start * GuiData->CharWidth,
                 Line * GuiData->CharHeight,
                 GuiData->LineBuffer,
                 RightChar - Start + 1);
    }

    if (Buff->CursorInfo.bVisible && GuiData->CursorBlinkOn &&
        !GuiData->ForceCursorOff)
    {
        GuiConsoleGetLogicalCursorPos(Buff,
                                      &CursorX,
                                      &CursorY);
        if (LeftChar <= CursorX && CursorX <= RightChar &&
            TopLine <= CursorY && CursorY <= BottomLine)
        {
            CursorHeight = (GuiData->CharHeight * Buff->CursorInfo.dwSize) / 100;
            if (CursorHeight < 1)
            {
                CursorHeight = 1;
            }
            From = Buff->Buffer + (Buff->CurrentY * Buff->MaxX + Buff->CurrentX) * 2 + 1;
            CursorBrush = CreateSolidBrush(GuiConsoleRGBFromAttribute(*From));
            OldBrush = SelectObject(hDC,
                                    CursorBrush);
            PatBlt(hDC,
                   CursorX * GuiData->CharWidth,
                   CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
                   GuiData->CharWidth,
                   CursorHeight,
                   PATCOPY);
            SelectObject(hDC,
                         OldBrush);
            DeleteObject(CursorBrush);
        }
    }

    LeaveCriticalSection(&Buff->Header.Lock);

    SelectObject(hDC,
                 OldFont);
}

static VOID FASTCALL
GuiConsoleHandlePaint(HWND hWnd, HDC hDCPaint)
{
    HDC hDC;
    PAINTSTRUCT ps;
    PCSRSS_CONSOLE Console;
    PGUI_CONSOLE_DATA GuiData;

    hDC = BeginPaint(hWnd, &ps);
    if (hDC != NULL &&

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?