netscape-revival
sun-java/awt/windows/awt_graphics.cpp
/*
* @(#)awt_graphics.cpp 1.56 96/01/05
*
* Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
#include "stdafx.h"
#include <limits.h>
#include <math.h>
#include "awt.h"
#include "awtapp.h"
#include "awt_fontmetrics.h"
#include "awt_graphics.h"
#include "awt_image.h"
#include "awt_label.h"
#include "awt_window.h"
#ifdef ENABLE_DEBUG_NEW
#define new DEBUG_NEW
#endif
#define OX (unhand(m_pJavaObject)->originX)
#define OY (unhand(m_pJavaObject)->originY)
#define TX(x) ((x) + OX)
#define TY(y) ((y) + OY)
static CMapPtrToPtr cleanupList;
AwtGraphics::AwtGraphics()
{
// Add the new object to the list of all AWT objects (debug only)
INITIALIZE_AWT_LIST_LINK("AwtGraphics");
m_hDC = NULL;
m_pSharedDC = NULL;
m_bPenSet = FALSE;
m_hPen = NULL;
m_color = RGB(0, 0, 0);
m_xorcolor = RGB(255, 255, 255);
m_bBrushSet = FALSE;
m_hBrush = NULL;
m_pFont = NULL;
m_bPaletteSelected = FALSE;
m_rectClip = CRect(0, 0, 0, 0);
m_bClipping = FALSE;
m_rop = R2_COPYPEN;
VERIFY(m_hClipRgn = ::CreateRectRgn(m_rectClip.left, m_rectClip.top, m_rectClip.right, m_rectClip.bottom));
cleanupList.SetAt(this, this);
}
AwtGraphics::~AwtGraphics()
{
if (m_pSharedDC != NULL) {
m_pSharedDC->Detach(this);
m_pSharedDC = NULL;
}
if (m_hPen != NULL) {
VERIFY(::DeleteObject(m_hPen));
m_hPen = NULL;
}
if (m_hBrush != NULL) {
VERIFY(::DeleteObject(m_hBrush));
m_hBrush = NULL;
}
VERIFY(::DeleteObject(m_hClipRgn));
m_hClipRgn = NULL;
cleanupList.RemoveKey(this);
// Remove the object from the list of all AWT objects (debug only)
REMOVE_AWT_LIST_LINK;
}
long AwtGraphics::HandleMsg(UINT nMsg, long p1, long p2, long p3,
long p4, long p5, long p6, long p7, long p8) {
switch (nMsg) {
case CREATE:
return (long)Create((Hsun_awt_win32_Win32Graphics *)p1, (AwtWindow*)p2);
break;
case CREATECOPY:
return (long)CreateCopy((Hsun_awt_win32_Win32Graphics *)p1, (AwtGraphics*)p2);
break;
default:
ASSERT(FALSE);
}
return 0;
}
HWND g_hWnd;
DWORD g_threadID;
HANDLE g_hClientEvent;
HANDLE g_hServerEvent;
HANDLE g_hThread;
DWORD ThreadFunc(DWORD);
HDC g_hResultDC;
AwtGraphics *AwtGraphics::Create(Hsun_awt_win32_Win32Graphics *pJavaObject, AwtCWnd *pWindow)
{
AwtGraphics *pGraphics = new AwtGraphics();
pGraphics->m_pJavaObject = pJavaObject;
cleanupList.RemoveKey(pGraphics); // window object will delete.
#if 0
// This code causes a significant resource leak, because the ReleaseDC
// in ~AwtGraphics() always fails.
if (GetApp()->m_bWin95OS) {
pGraphics->m_hDC = ::GetDC(pWindow->m_hWnd);
} else {
#endif
if (pWindow->m_pSharedDC == NULL) {
if (g_threadID == NULL) {
g_hClientEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
g_hServerEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
if ((g_hThread = ::CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)ThreadFunc, 0, THREAD_TERMINATE, &g_threadID)) == NULL) {
SignalError(0, JAVAPKG "OutOfMemoryError", 0);
}
ASSERT(g_threadID != NULL);
}
g_hWnd = pWindow->m_hWnd;
VERIFY(::SetEvent(g_hServerEvent));
VERIFY(::WaitForSingleObject(g_hClientEvent, INFINITE) != WAIT_FAILED);
VERIFY(::ResetEvent(g_hClientEvent));
pWindow->m_pSharedDC = new AwtSharedDC(pWindow, g_hResultDC);
}
pGraphics->m_pSharedDC = pWindow->m_pSharedDC;
pGraphics->m_pSharedDC->Attach();
#if 0
}
#endif
if (pWindow->IsKindOf(RUNTIME_CLASS(AwtWindow))) {
pGraphics->SetColor(((AwtWindow*)pWindow)->m_bgfgColor[FALSE]);
} else if (pWindow->IsKindOf(RUNTIME_CLASS(AwtLabel))) {
pGraphics->SetColor(((AwtLabel*)pWindow)->m_pParent->m_bgfgColor[FALSE]);
}
// Offset the origin so that 0,0 is the top-left of the frame,
// instead of the client window, for top-level windows.
CWnd *parent = pWindow->GetParent();
CWnd *pWnd = parent;
while (pWnd != NULL && !pWnd->IsKindOf(RUNTIME_CLASS(MainFrame)))
pWnd = pWnd->GetParent();
MainFrame* frame = (MainFrame*)pWnd;
if (frame != NULL && parent->m_hWnd == frame->m_hWnd) {
long insetX;
long insetY;
frame->SubtractInsetPoint(insetX, insetY);
unhand(pJavaObject)->originX += insetX;
unhand(pJavaObject)->originY += insetY;
}
return pGraphics;
}
AwtGraphics *AwtGraphics::CreateCopy(Hsun_awt_win32_Win32Graphics *pJavaObject, AwtGraphics *pSource)
{
AwtGraphics *pGraphics;
AwtCWnd *pWnd = pSource->GetWnd();
if (pWnd != NULL) {
pGraphics = AwtGraphics::Create(pJavaObject, pWnd);
} else {
pGraphics = new AwtGraphics();
pGraphics->m_pJavaObject = pJavaObject;
pGraphics->m_pSharedDC = pSource->m_pSharedDC;
pGraphics->m_pSharedDC->Attach();
}
if (pSource->m_bClipping) {
int x = pSource->m_rectClip.left;
int y = pSource->m_rectClip.top;
int w = pSource->m_rectClip.right - x;
int h = pSource->m_rectClip.bottom - y;
x -= unhand(pJavaObject)->originX;
y -= unhand(pJavaObject)->originY;
pGraphics->SetClipRect(x, y, w, h);
}
pGraphics->SetRop(pSource->m_rop, pSource->m_color, RGB(0, 0, 0));
pGraphics->SetColor(pSource->m_color);
pGraphics->SetFont(pSource->m_pFont);
return pGraphics;
}
AwtGraphics *AwtGraphics::Create(Hsun_awt_win32_Win32Graphics *pJavaObject, AwtImage *pImage)
{
AwtGraphics *pGraphics = new AwtGraphics();
pGraphics->m_pJavaObject = pJavaObject;
pGraphics->m_pSharedDC = pImage->m_pSharedDC;
pGraphics->m_pSharedDC->Attach();
return pGraphics;
}
void AwtGraphics::Dispose() {
delete this;
}
void AwtGraphics::ValidateDC() {
m_hDC = m_pSharedDC->GrabDC(this);
if (m_hDC == NULL) {
return;
}
if (m_pFont != NULL) {
VERIFY(::SelectObject(m_hDC, m_pFont->m_hObject) != NULL);
}
VERIFY(::SetTextColor(m_hDC, m_color) != CLR_INVALID);
VERIFY(::SetROP2(m_hDC, m_rop));
m_bPaletteSelected = FALSE;
if (m_bClipping) {
VERIFY(::SelectClipRgn(m_hDC, m_hClipRgn) != ERROR);
}
}
void AwtGraphics::InvalidateDC() {
SetPenColor(FALSE);
SetBrushColor(FALSE);
::SelectObject(m_hDC, ::GetStockObject(SYSTEM_FONT));
if (m_bPaletteSelected) {
::SelectObject(m_hDC, ::GetStockObject(DEFAULT_PALETTE));
m_bPaletteSelected = FALSE;
}
if (m_bClipping) {
::SelectClipRgn(m_hDC, NULL);
}
m_hDC = NULL;
}
static COLORREF XorResult(COLORREF fgcolor, COLORREF xorcolor) {
COLORREF c;
if (AwtImage::m_bitspixel > 8) {
c = (fgcolor & 0xff000000) | ((fgcolor ^ xorcolor) & 0x00ffffff);
} else {
c = PALETTEINDEX(GetNearestPaletteIndex(AwtImage::m_hPal, fgcolor) ^
GetNearestPaletteIndex(AwtImage::m_hPal, xorcolor));
}
return c;
}
void AwtGraphics::SetColor(COLORREF color)
{
if (m_rop == R2_XORPEN) {
ChangeColor(XorResult(color, m_xorcolor));
} else {
ChangeColor(color);
}
}
void AwtGraphics::ChangeColor(COLORREF color)
{
if (m_color != color) {
m_color = color;
if (m_hDC != NULL) {
VERIFY(::SetTextColor(m_hDC, color) != CLR_INVALID);
}
if (m_hPen != NULL) {
if (m_hDC != NULL) {
SetPenColor(FALSE);
}
VERIFY(::DeleteObject(m_hPen));
m_hPen = NULL;
}
if (m_hBrush != NULL) {
if (m_hDC != NULL) {
SetBrushColor(FALSE);
}
VERIFY(::DeleteObject(m_hBrush));
m_hBrush = NULL;
}
}
}
void AwtGraphics::SetFont(AwtFont *pFont)
{
if (m_pFont != pFont) {
if (m_hDC != NULL) {
VERIFY(::SelectObject(m_hDC, pFont->m_hObject) != NULL);
}
m_pFont = pFont;
}
}
void AwtGraphics::SetRop(int rop, COLORREF fgcolor, COLORREF color)
{
if (m_rop != rop) {
if (m_hDC != NULL) {
VERIFY(::SetROP2(m_hDC, rop));
}
m_rop = rop;
}
if (m_rop == R2_XORPEN) {
ChangeColor(XorResult(fgcolor, color));
m_xorcolor = color;
} else {
ChangeColor(fgcolor);
}
}
void AwtGraphics::DrawLine(long nX1, long nY1, long nX2, long nY2)
{
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
SetPenColor(TRUE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::MoveToEx(hDC, TX(nX1), TY(nY1), NULL));
VERIFY(::LineTo(hDC, TX(nX2), TY(nY2)));
// Paint the end-point.
VERIFY(::LineTo(hDC, TX(nX2+1), TY(nY2)));
//GdiFlush();
}
void AwtGraphics::ClearRect(long nX, long nY, long nW, long nH)
{
if (nW <= 0 || nH <= 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
HBRUSH hBrush;
AwtCWnd *pWnd = GetWnd();
if (pWnd != NULL) {
// Use the brush that the window cached
COLORREF color;
if (pWnd->IsKindOf(RUNTIME_CLASS(AwtWindow))) {
color = ((AwtWindow*)pWnd)->m_bgfgColor[FALSE];
} else if (pWnd->IsKindOf(RUNTIME_CLASS(AwtLabel))) {
color = ((AwtLabel*)pWnd)->m_pParent->m_bgfgColor[FALSE];
}
hBrush = GetApp()->GetBrush(color);
} else {
hBrush = (HBRUSH)::GetStockObject( WHITE_BRUSH );
}
HBRUSH hOldBrush = (HBRUSH) ::SelectObject(hDC, hBrush);
CALLINGWINDOWS(GetWnd()->m_hWnd);
::FillRect(hDC, CRect(TX(nX), TY(nY), TX(nX+nW), TY(nY+nH)), hBrush);
VERIFY(::SelectObject(hDC, hOldBrush));
//
// The temporary HBRUSH does not need to be deleted since it is either
// cached or a stock windows object
//
//GdiFlush();
}
void AwtGraphics::FillRect(long nX, long nY, long nW, long nH)
{
if (nW <= 0 || nH <= 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
SetBrushColor(TRUE);
SetPenColor(FALSE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Rectangle(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1)));
//GdiFlush();
}
void AwtGraphics::RoundRect(long nX, long nY, long nW, long nH, long nArcW, long nArcH)
{
if (nW < 0 || nH < 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
SetPenColor(TRUE);
SetBrushColor(FALSE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
::RoundRect(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1),
nArcW, nArcH);
}
void AwtGraphics::FillRoundRect(long nX, long nY, long nW, long nH, long nArcW, long nArcH)
{
if (nW <= 0 || nH <= 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
SetPenColor(FALSE);
SetBrushColor(TRUE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
::RoundRect(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1),
nArcW, nArcH);
}
void AwtGraphics::Ellipse(long nX, long nY, long nW, long nH)
{
if (nW < 0 || nH < 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
SetPenColor(TRUE);
SetBrushColor(FALSE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Ellipse(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1)));
}
void AwtGraphics::FillEllipse(long nX, long nY, long nW, long nH)
{
if (nW <= 0 || nH <= 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
SetPenColor(FALSE);
SetBrushColor(TRUE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Ellipse(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1)));
}
void AngleToCoord(long nAngle, long nW, long nH, long *nX, long *nY) {
const double pi = 3.1415926535;
const double toRadians = 2 * pi / 360;
*nX = (long)(cos((double)nAngle * toRadians) * nW);
*nY = -(long)(sin((double)nAngle * toRadians) * nH);
}
void AwtGraphics::Arc(long nX, long nY, long nW, long nH, long nStartAngle, long nEndAngle)
{
if (nW < 0 || nH < 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
long nSX, nSY, nDX, nDY;
BOOL bEndAngleNeg = nEndAngle < 0;
nEndAngle += nStartAngle;
if (bEndAngleNeg) {
// swap angles
long tmp = nStartAngle;
nStartAngle = nEndAngle;
nEndAngle = tmp;
}
AngleToCoord(nStartAngle, nW, nH, &nSX, &nSY);
nSX += nX + nW/2;
nSY += nY + nH/2;
AngleToCoord(nEndAngle, nW, nH, &nDX, &nDY);
nDX += nX + nW/2;
nDY += nY + nH/2;
SetPenColor(TRUE);
SetBrushColor(FALSE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Arc(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1),
TX(nSX), TY(nSY), TX(nDX), TY(nDY)));
}
void AwtGraphics::FillArc(long nX, long nY, long nW, long nH, long nStartAngle, long nEndAngle)
{
if (nW <= 0 || nH <= 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
long nSX, nSY, nDX, nDY;
BOOL bEndAngleNeg = nEndAngle < 0;
nEndAngle += nStartAngle;
if (bEndAngleNeg) {
// swap angles
long tmp = nStartAngle;
nStartAngle = nEndAngle;
nEndAngle = tmp;
}
AngleToCoord(nStartAngle, nW, nH, &nSX, &nSY);
nSX += nX + nW/2;
nSY += nY + nH/2;
AngleToCoord(nEndAngle, nW, nH, &nDX, &nDY);
nDX += nX + nW/2;
nDY += nY + nH/2;
SetPenColor(FALSE);
SetBrushColor(TRUE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Pie(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1),
TX(nSX), TY(nSY), TX(nDX), TY(nDY)));
}
void AwtGraphics::ChangePen(BOOL bSetPen)
{
if (bSetPen) {
if (!m_bPaletteSelected) {
m_bPaletteSelected = TRUE;
VERIFY(::SelectPalette(m_hDC, AwtImage::m_hPal, FALSE));
UINT result = ::RealizePalette(m_hDC);
}
if (m_hPen == NULL) {
m_hPen = ::CreatePen(PS_SOLID, 1, m_color);
m_bPenSet = FALSE;
}
if (!m_bPenSet) {
::SelectObject(m_hDC, m_hPen);
m_bPenSet = TRUE;
}
} else if (m_bPenSet) {
::SelectObject(m_hDC, ::GetStockObject(NULL_PEN));
m_bPenSet = FALSE;
}
}
void AwtGraphics::ChangeBrush(BOOL bSetBrush)
{
if (bSetBrush) {
if (!m_bPaletteSelected) {
m_bPaletteSelected = TRUE;
VERIFY(::SelectPalette(m_hDC, AwtImage::m_hPal, FALSE));
UINT result = ::RealizePalette(m_hDC);
}
if (m_hBrush == NULL) {
m_hBrush = ::CreateSolidBrush(m_color);
m_bBrushSet = FALSE;
}
if (!m_bBrushSet) {
::SelectObject(m_hDC, m_hBrush);
m_bBrushSet = TRUE;
}
} else if (m_bBrushSet) {
::SelectObject(m_hDC, ::GetStockObject(NULL_BRUSH));
m_bBrushSet = FALSE;
}
}
void AwtGraphics::Polygon(POINT *pPoints, int nPoints)
{
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
int i;
POINT *p = pPoints;
for (i=0; i < nPoints; i++) {
p->x = TX(p->x);
p->y = TY(p->y);
p++;
}
SetPenColor(TRUE);
SetBrushColor(FALSE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Polyline(hDC, pPoints, nPoints));
//GdiFlush();
}
void AwtGraphics::FillPolygon(POINT *pPoints, int nPoints)
{
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
int i;
POINT *p = pPoints;
for (i=0; i < nPoints; i++) {
p->x = TX(p->x);
p->y = TY(p->y);
p++;
}
SetPenColor(FALSE);
SetBrushColor(TRUE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Polygon(hDC, pPoints, nPoints));
//GdiFlush();
}
void AwtGraphics::DrawRect(long nX, long nY, long nW, long nH)
{
if (nW < 0 || nH < 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
SetPenColor(TRUE);
SetBrushColor(FALSE);
CALLINGWINDOWS(GetWnd()->m_hWnd);
VERIFY(::Rectangle(hDC, TX(nX), TY(nY), TX(nX+nW+1), TY(nY+nH+1)));
//GdiFlush();
}
void AwtGraphics::DrawString(char *pzString, long nX, long nY)
{
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
if (m_pFont != NULL && m_pFont->m_nAscent < 0) {
AwtFontMetrics::SetFontAscent(m_pFont);
}
if (m_rop == R2_XORPEN) {
BeginPath(hDC);
}
VERIFY(::TextOut(hDC, TX(nX), TY(nY - (m_pFont ? m_pFont->m_nAscent : 0)),
pzString, strlen(pzString)));
if (m_rop == R2_XORPEN) {
EndPath(hDC);
SetBrushColor(TRUE);
SetPenColor(FALSE);
FillPath(hDC);
}
//GdiFlush();
free(pzString);
}
long AwtGraphics::DrawStringWidth(char *pzString, long nX, long nY)
{
HDC hDC = GetDC();
if (hDC == NULL) {
return 0;
}
CSize size;
if (m_pFont != NULL && m_pFont->m_nAscent < 0) {
AwtFontMetrics::SetFontAscent(m_pFont);
}
if (m_rop == R2_XORPEN) {
BeginPath(hDC);
}
VERIFY(::TextOut(hDC, TX(nX), TY(nY - (m_pFont ? m_pFont->m_nAscent : 0)),
pzString, strlen(pzString)));
if (m_rop == R2_XORPEN) {
EndPath(hDC);
SetBrushColor(TRUE);
SetPenColor(FALSE);
FillPath(hDC);
}
VERIFY(::GetTextExtentPoint32(hDC, pzString, strlen(pzString), &size));
//GdiFlush();
free(pzString);
return size.cx;
}
void AwtGraphics::DrawImage(AwtImage *pImage, long nX, long nY,
struct Hjava_awt_Color *c)
{
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
int xormode = (m_rop == R2_XORPEN);
HBRUSH hOldBrush;
HBRUSH hBrush;
if (xormode) {
SetPenColor(FALSE);
hBrush = ::CreateSolidBrush(m_xorcolor);
hOldBrush = (HBRUSH) ::SelectObject(hDC, hBrush);
}
if (pImage->m_pSharedDC != NULL) {
HDC hMemDC = pImage->m_pSharedDC->GetDC();
if (hMemDC != NULL) {
// See comment at top of AwtImage::Draw about BitBlt rop codes...
VERIFY(::BitBlt(hDC, TX(nX), TY(nY),
pImage->m_nDstW, pImage->m_nDstH,
hMemDC, 0, 0,
xormode ? 0x00960000 : SRCCOPY));
}
} else {
pImage->Draw(hDC, TX(nX), TY(nY), xormode, m_xorcolor, hBrush, c);
}
if (xormode) {
VERIFY(::SelectObject(hDC, hOldBrush));
VERIFY(::DeleteObject(hBrush));
}
m_bPaletteSelected = TRUE;
}
void AwtGraphics::CopyArea(long nDstX, long nDstY, long nX, long nY, long nW, long nH)
{
if (nW <= 0 || nH <= 0) {
return;
}
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
CRect rectClip;
long dX = TX(nDstX)-TX(nX);
long dY = TY(nDstY)-TY(nY);
CRgn rgnUpdate;
CRect rectSrc(TX(nX), TY(nY),
TX(nX+nW), TY(nY+nH));
CRect rectDst = rectSrc + CPoint(dX, dY);
rgnUpdate.CreateRectRgn(0, 0, 0, 0);
if (!m_bClipping) {
rectClip.UnionRect(rectSrc, rectDst);
} else {
VERIFY(::GetRgnBox(m_hClipRgn, &rectClip) != ERROR);
}
VERIFY(::ScrollDC(hDC, dX, dY, rectSrc, rectClip, (HRGN)rgnUpdate.m_hObject, NULL));
// If the src-dst rectangle equals the update rectangle, then don't
// bother invalidating the region; it's assumed the client will
// repaint the pixels in src-dst.
VERIFY(rgnUpdate.GetRgnBox(&rectClip) != ERROR);
rectSrc.SubtractRect(rectSrc, rectDst);
AwtCWnd *pWnd = GetWnd();
if (rectSrc != rectClip && pWnd != NULL) {
// REMIND: must somehow send exposures for bitmaps...
pWnd->InvalidateRgn(&rgnUpdate);
}
}
void AwtGraphics::SetClipRect(long nX, long nY, long nW, long nH)
{
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
int x1, y1, x2, y2;
x1 = TX(nX);
y1 = TY(nY);
if (nW <= 0 || nH <= 0) {
x2 = x1;
y2 = y1;
} else {
x2 = x1 + nW;
y2 = y1 + nH;
}
if (!m_bClipping ||
m_rectClip.left != x1 || m_rectClip.top != y1 ||
m_rectClip.right != x2 || m_rectClip.bottom != y2) {
if (m_bClipping) {
m_rectClip &= CRect(x1, y1, x2, y2);
} else {
m_rectClip = CRect(x1, y1, x2, y2);
}
::SetRectRgn(m_hClipRgn,
m_rectClip.left,
m_rectClip.top,
m_rectClip.right,
m_rectClip.bottom);
}
m_bClipping = TRUE;
VERIFY(::SelectClipRgn(hDC, m_hClipRgn) != ERROR);
}
void AwtGraphics::ClearClipRect()
{
HDC hDC = GetDC();
if (hDC == NULL) {
return;
}
m_bClipping = FALSE;
VERIFY(::SelectClipRgn(hDC, NULL) != ERROR);
}
void AwtGraphics::GetClipRect(RECT *rect)
{
if (m_bClipping) {
rect->left = (m_rectClip.left - OX);
rect->top = (m_rectClip.top - OY);
rect->right = (m_rectClip.right - OX);
rect->bottom = (m_rectClip.bottom - OY);
} else {
rect->left = LONG_MIN;
rect->top = LONG_MIN;
rect->right = LONG_MAX;
rect->bottom = LONG_MAX;
}
}
void AwtGraphics::Cleanup() {
// Delete any AwtGraphics objects which weren't disposed.
POSITION pos = cleanupList.GetStartPosition();
while (pos != NULL) {
void *key, *p;
cleanupList.GetNextAssoc(pos, key, p);
AwtGraphics* pGraphics = (AwtGraphics*)p;
if (pGraphics != NULL) {
delete pGraphics;
}
}
cleanupList.RemoveAll();
::TerminateThread(g_hThread, 0);
::CloseHandle(g_hServerEvent);
::CloseHandle(g_hClientEvent);
::CloseHandle(g_hThread);
}
// The purpose of this thread is simply to create DC's. The problem
// is that if the thread that creates the DC goes away, the DC becomes invalid.
// Also, we can't use the WServer thread to create the DC's because
// that would introduce a deadlock.
// <<Need to worry about cleaning up this thread.>>
DWORD ThreadFunc(DWORD dwParam)
{
while (TRUE) {
VERIFY(::WaitForSingleObject(g_hServerEvent, INFINITE) != WAIT_FAILED);
VERIFY(::ResetEvent(g_hServerEvent));
VERIFY(g_hResultDC = ::GetDC(g_hWnd));
VERIFY(::SetBkMode(g_hResultDC, TRANSPARENT) != NULL);
::SelectObject(g_hResultDC, ::GetStockObject(NULL_BRUSH));
::SelectObject(g_hResultDC, ::GetStockObject(NULL_PEN));
GdiFlush();
VERIFY(::SetEvent(g_hClientEvent));
}
return 0;
}
HDC AwtSharedDC::GrabDC(AwtGraphics *pNewOwner) {
if (m_pOwner != NULL) {
m_pOwner->InvalidateDC();
}
if (m_hDC != NULL) {
m_pOwner = pNewOwner;
}
return m_hDC;
}
void AwtSharedDC::Detach(AwtGraphics *pOldOwner) {
if (pOldOwner == NULL) {
// Must be the destination drawable that is detaching
FreeDC();
} else if (m_pOwner == pOldOwner) {
// Release this Device Context and leave it "ownerless"
m_pOwner->InvalidateDC();
m_pOwner = NULL;
}
if (--m_useCount == 0) {
delete this;
}
}
void AwtSharedDC::FreeDC() {
if (m_hDC == NULL) {
return;
}
if (m_pOwner != NULL) {
m_pOwner->InvalidateDC();
m_pOwner = NULL;
}
if (m_pWnd == NULL) {
VERIFY(::DeleteDC(m_hDC));
} else {
::ReleaseDC(m_pWnd->m_hWnd, m_hDC);
m_pWnd = NULL;
}
m_hDC = NULL;
}