wine/windows/painting.c
Alexandre Julliard ca22b33dad Release 960712
Fri Jul 12 17:43:05 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [controls/scroll.c]
	Use Win32 heap functions to allocate scroll-bar info structure.

	* [debugger/dbg.y] [debugger/registers.c]
	Added support for FS and GS segment registers.
	Check that segment registers value are OK before returning from
	the signal handler.

	* [tools/build.c] [if1632/relay.c] [loader/builtin.c]
	Changed relay debugging for Win32 function: the relay code now
	passes the entry point address instead of the function name.

	* [tools/build.c] [miscemu/*.c]
	Added support for data entry points in Win32 DLLs.
	Added 'cdecl' function type for Win32.
	For 'register' function, the relay code now passes a pointer to
	the SIGCONTEXT structure.
	
	* [include/registers.h] [include/wine.h]
	Moved SIGCONTEXT structure definition in registers.h.

	* [loader/pe_image.c]
	Don't die at once if some Win32 entry points cannot be found, but
	set them to NULL, just like we do for Win16. This allows some
	programs to go further before crashing.

	* [loader/task.c] [loader/main.c]
	Moved global initializations from InitTask() to MAIN_Init(), as
	they no longer need a task context with the new SEGPTR heap functions.

	* [memory/string.c]
	Added lstrcpynAtoW and lstrcpynWtoA; not real API functions, but
 	very convenient.

	* [windows/graphics.c]
	Partially implemented DrawEdge().

	* [windows/timer.c] [windows/caret.c]
	Implemented Win32 timer handling. Updated caret management to use
	Win32 timers (avoids having to use a Win16 callback).

	* [windows/win.c]
	Prevent programs from setting some style bits with
	SetWindowLong(). This should fix some BadMatch crashes.
	Link new windows at the end of the linked list.

	* [windows/winpos.c]
	Don't try to activate a child window in ShowWindow().

	* [windows/winproc.c]
	Added a 32->32 thunk to support Ansi-Unicode translation.

Wed Jul 10 22:11:12 1996  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [files/directory.c]
	Additional (undocumented) return value for GetTempDrive() added.

	* [files/dos_fs.c] [files/file.c] [include/windows.h]
	GetTempFileName32* added.
	GetShortPathName* added.

	* [memory/string.c]
	Win16 lstrcpy() can get NULL ptrs as argument and survive.

	* [misc/lzexpand.c]
	LZOpenFile(): also try opening with compressed filename if normal
 	open fails.

	* [misc/ole2nls.c] [misc/lstr.c] [include/windows.h]
	Char* added.
	CompareString* added.

Sun Jul  7 01:22:14 1996  Jukka Iivonen <iivonen@cc.helsinki.fi>

	* [objects/font.c] [if1632/gdi32.spec]
	CreateFontIndirect32A and CreateFontIndirect32W added.

	* [misc/ole2nls.c]
	GetUserDefaultLCID return values updated for new languages.
	Finnish support added for GetLocaleInfoA.

	* [object/palette] [gdi32.spec]
	RealizePalette32 and SelectPalette32 added.
	
Sat Jul  6 17:27:30 1996  Ronan Waide  <root@waider.ie>

	* [misc/shell.c]
	Fixup for SHELL_FindExecutable so that File->Run from progman
	works once more. Still needs some more fixups - grep for FIXME in
	this file.
1996-07-12 19:02:39 +00:00

561 lines
16 KiB
C

/*
* Window painting functions
*
* Copyright 1993, 1994, 1995 Alexandre Julliard
*/
#include <stdio.h>
#include <X11/Xlib.h>
#include "win.h"
#include "queue.h"
#include "gdi.h"
#include "dce.h"
#include "stddebug.h"
/* #define DEBUG_WIN */
#include "debug.h"
/* Last CTLCOLOR id */
#define CTLCOLOR_MAX CTLCOLOR_STATIC
/***********************************************************************
* WIN_UpdateNCArea
*
*/
void WIN_UpdateNCArea(WND* wnd, BOOL bUpdate)
{
POINT16 pt = {0, 0};
HRGN hClip = 1;
dprintf_nonclient(stddeb,"NCUpdate: hwnd %04x, hrgnUpdate %04x\n",
wnd->hwndSelf, wnd->hrgnUpdate );
/* desktop window doesn't have nonclient area */
if(wnd == WIN_GetDesktop())
{
wnd->flags &= ~WIN_NEEDS_NCPAINT;
return;
}
if( wnd->hrgnUpdate > 1 )
{
ClientToScreen16(wnd->hwndSelf, &pt);
hClip = CreateRectRgn( 0, 0, 0, 0 );
if (!CombineRgn(hClip, wnd->hrgnUpdate, 0, RGN_COPY) )
{
DeleteObject(hClip);
hClip = 1;
}
else
OffsetRgn(hClip, pt.x, pt.y);
if (bUpdate)
{
/* exclude non-client area from update region */
HRGN hrgn = CreateRectRgn(0, 0, wnd->rectClient.right - wnd->rectClient.left,
wnd->rectClient.bottom - wnd->rectClient.top);
if (hrgn && (CombineRgn(wnd->hrgnUpdate, wnd->hrgnUpdate,
hrgn, RGN_AND) == NULLREGION))
{
DeleteObject(wnd->hrgnUpdate);
wnd->hrgnUpdate = 1;
}
DeleteObject( hrgn );
}
}
wnd->flags &= ~WIN_NEEDS_NCPAINT;
if ((wnd->hwndSelf == GetActiveWindow()) &&
!(wnd->flags & WIN_NCACTIVATED))
{
wnd->flags |= WIN_NCACTIVATED;
if( hClip > 1) DeleteObject(hClip);
hClip = 1;
}
if (hClip) SendMessage16( wnd->hwndSelf, WM_NCPAINT, hClip, 0L );
if (hClip > 1) DeleteObject( hClip );
}
/***********************************************************************
* BeginPaint16 (USER.39)
*/
HDC16 BeginPaint16( HWND16 hwnd, LPPAINTSTRUCT16 lps )
{
HRGN hrgnUpdate;
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return 0;
wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;
if (wndPtr->flags & WIN_NEEDS_NCPAINT) WIN_UpdateNCArea( wndPtr, TRUE );
if (((hrgnUpdate = wndPtr->hrgnUpdate) != 0) ||
(wndPtr->flags & WIN_INTERNAL_PAINT))
QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
wndPtr->hrgnUpdate = 0;
wndPtr->flags &= ~WIN_INTERNAL_PAINT;
HideCaret( hwnd );
dprintf_win(stddeb,"hrgnUpdate = %04x, ", hrgnUpdate);
lps->hdc = GetDCEx( hwnd, hrgnUpdate, DCX_INTERSECTRGN | DCX_WINDOWPAINT | DCX_USESTYLE );
dprintf_win(stddeb,"hdc = %04x\n", lps->hdc);
/* pseudocode from "Internals" doesn't delete hrgnUpdate - yet another clue
that ReleaseDC should take care of it (hence DCX_KEEPCLIPRGN) */
if (!lps->hdc)
{
fprintf(stderr, "GetDCEx() failed in BeginPaint(), hwnd=%04x\n", hwnd);
return 0;
}
GetRgnBox16( InquireVisRgn(lps->hdc), &lps->rcPaint );
DPtoLP16( lps->hdc, (LPPOINT16)&lps->rcPaint, 2 );
if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
{
wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
lps->fErase = !SendMessage16(hwnd, WM_ERASEBKGND, (WPARAM)lps->hdc, 0);
}
else lps->fErase = TRUE;
return lps->hdc;
}
/***********************************************************************
* BeginPaint32 (USER32.9)
*/
HDC32 BeginPaint32( HWND32 hwnd, PAINTSTRUCT32 *lps )
{
PAINTSTRUCT16 ps;
BeginPaint16( hwnd, &ps );
lps->hdc = (HDC32)ps.hdc;
lps->fErase = ps.fErase;
lps->rcPaint.top = ps.rcPaint.top;
lps->rcPaint.left = ps.rcPaint.left;
lps->rcPaint.right = ps.rcPaint.right;
lps->rcPaint.bottom = ps.rcPaint.bottom;
lps->fRestore = ps.fRestore;
lps->fIncUpdate = ps.fIncUpdate;
return lps->hdc;
}
/***********************************************************************
* EndPaint16 (USER.40)
*/
BOOL16 EndPaint16( HWND16 hwnd, const PAINTSTRUCT16* lps )
{
ReleaseDC( hwnd, lps->hdc );
ShowCaret( hwnd );
return TRUE;
}
/***********************************************************************
* EndPaint32 (USER32.175)
*/
BOOL32 EndPaint32( HWND32 hwnd, const PAINTSTRUCT32 *lps )
{
ReleaseDC( hwnd, (HDC16)lps->hdc );
ShowCaret( hwnd );
return TRUE;
}
/***********************************************************************
* FillWindow (USER.324)
*/
void FillWindow( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc, HBRUSH16 hbrush )
{
RECT16 rect;
GetClientRect16( hwnd, &rect );
DPtoLP16( hdc, (LPPOINT16)&rect, 2 );
PaintRect( hwndParent, hwnd, hdc, hbrush, &rect );
}
/***********************************************************************
* PaintRect (USER.325)
*/
void PaintRect( HWND16 hwndParent, HWND16 hwnd, HDC16 hdc,
HBRUSH16 hbrush, const RECT16 *rect)
{
/* Send WM_CTLCOLOR message if needed */
if ((UINT32)hbrush <= CTLCOLOR_MAX)
{
if (!hwndParent) return;
hbrush = (HBRUSH)SendMessage32A( hwndParent,
WM_CTLCOLORMSGBOX + (UINT32)hbrush,
(WPARAM)hdc, (LPARAM)hwnd );
}
if (hbrush) FillRect16( hdc, rect, hbrush );
}
/***********************************************************************
* GetControlBrush (USER.326)
*/
HBRUSH GetControlBrush( HWND hwnd, HDC hdc, WORD control )
{
return (HBRUSH)SendMessage32A( GetParent(hwnd), WM_CTLCOLOR+control,
(WPARAM)hdc, (LPARAM)hwnd );
}
/***********************************************************************
* RedrawWindow32 (USER32.425)
*/
BOOL32 RedrawWindow32( HWND32 hwnd, const RECT32 *rectUpdate,
HRGN32 hrgnUpdate, UINT32 flags )
{
HRGN hrgn;
RECT32 rectClient;
WND * wndPtr;
if (!hwnd) hwnd = GetDesktopWindow();
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
if (!IsWindowVisible(hwnd) || (wndPtr->flags & WIN_NO_REDRAW))
return TRUE; /* No redraw needed */
if (rectUpdate)
{
dprintf_win(stddeb, "RedrawWindow: %04x %d,%d-%d,%d %04x flags=%04x\n",
hwnd, rectUpdate->left, rectUpdate->top,
rectUpdate->right, rectUpdate->bottom, hrgnUpdate, flags );
}
else
{
dprintf_win(stddeb, "RedrawWindow: %04x NULL %04x flags=%04x\n",
hwnd, hrgnUpdate, flags);
}
GetClientRect32( hwnd, &rectClient );
if (flags & RDW_INVALIDATE) /* Invalidate */
{
int rgnNotEmpty = COMPLEXREGION;
if (wndPtr->hrgnUpdate > 1) /* Is there already an update region? */
{
if ((hrgn = hrgnUpdate) == 0)
hrgn = CreateRectRgnIndirect32( rectUpdate ? rectUpdate :
&rectClient );
rgnNotEmpty = CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate, hrgn, RGN_OR );
if (!hrgnUpdate) DeleteObject( hrgn );
}
else /* No update region yet */
{
if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
if (hrgnUpdate)
{
wndPtr->hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
rgnNotEmpty = CombineRgn( wndPtr->hrgnUpdate, hrgnUpdate, 0, RGN_COPY );
}
else wndPtr->hrgnUpdate = CreateRectRgnIndirect32( rectUpdate ?
rectUpdate : &rectClient );
}
if (flags & RDW_FRAME) wndPtr->flags |= WIN_NEEDS_NCPAINT;
/* check for bogus update region */
if ( rgnNotEmpty == NULLREGION )
{
wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
DeleteObject(wndPtr->hrgnUpdate);
wndPtr->hrgnUpdate=0;
if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
}
else
if (flags & RDW_ERASE) wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
flags |= RDW_FRAME; /* Force invalidating the frame of children */
}
else if (flags & RDW_VALIDATE) /* Validate */
{
/* We need an update region in order to validate anything */
if (wndPtr->hrgnUpdate > 1)
{
if (!hrgnUpdate && !rectUpdate)
{
/* Special case: validate everything */
DeleteObject( wndPtr->hrgnUpdate );
wndPtr->hrgnUpdate = 0;
}
else
{
if ((hrgn = hrgnUpdate) == 0)
hrgn = CreateRectRgnIndirect32( rectUpdate );
if (CombineRgn( wndPtr->hrgnUpdate, wndPtr->hrgnUpdate,
hrgn, RGN_DIFF ) == NULLREGION)
{
DeleteObject( wndPtr->hrgnUpdate );
wndPtr->hrgnUpdate = 0;
}
if (!hrgnUpdate) DeleteObject( hrgn );
}
if (!wndPtr->hrgnUpdate) /* No more update region */
if (!(wndPtr->flags & WIN_INTERNAL_PAINT))
QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
}
if (flags & RDW_NOFRAME) wndPtr->flags &= ~WIN_NEEDS_NCPAINT;
if (flags & RDW_NOERASE) wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
}
/* Set/clear internal paint flag */
if (flags & RDW_INTERNALPAINT)
{
if ( wndPtr->hrgnUpdate <= 1 && !(wndPtr->flags & WIN_INTERNAL_PAINT))
QUEUE_IncPaintCount( wndPtr->hmemTaskQ );
wndPtr->flags |= WIN_INTERNAL_PAINT;
}
else if (flags & RDW_NOINTERNALPAINT)
{
if ( wndPtr->hrgnUpdate <= 1 && (wndPtr->flags & WIN_INTERNAL_PAINT))
QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
wndPtr->flags &= ~WIN_INTERNAL_PAINT;
}
/* Erase/update window */
if (flags & RDW_UPDATENOW)
{
if (wndPtr->hrgnUpdate) SendMessage16( hwnd, WM_PAINT, 0, 0 );
}
else if (flags & RDW_ERASENOW)
{
if (wndPtr->flags & WIN_NEEDS_NCPAINT)
WIN_UpdateNCArea( wndPtr, FALSE);
if (wndPtr->flags & WIN_NEEDS_ERASEBKGND)
{
HDC hdc = GetDCEx( hwnd, wndPtr->hrgnUpdate,
DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN | DCX_WINDOWPAINT);
if (hdc)
{
/* Don't send WM_ERASEBKGND to icons */
/* (WM_ICONERASEBKGND is sent during processing of WM_NCPAINT) */
if (!(wndPtr->dwStyle & WS_MINIMIZE) ||
!wndPtr->class->hIcon)
{
if (SendMessage16( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ))
wndPtr->flags &= ~WIN_NEEDS_ERASEBKGND;
}
ReleaseDC( hwnd, hdc );
}
}
}
/* Recursively process children */
if (!(flags & RDW_NOCHILDREN) &&
((flags & RDW_ALLCHILDREN) || !(wndPtr->dwStyle & WS_CLIPCHILDREN)))
{
if (hrgnUpdate)
{
HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
if (!hrgn) return TRUE;
for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
{
CombineRgn( hrgn, hrgnUpdate, 0, RGN_COPY );
OffsetRgn( hrgn, -wndPtr->rectClient.left,
-wndPtr->rectClient.top );
RedrawWindow32( wndPtr->hwndSelf, NULL, hrgn, flags );
}
DeleteObject( hrgn );
}
else
{
RECT32 rect;
for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
{
if (rectUpdate)
{
rect = *rectUpdate;
OffsetRect32( &rect, -wndPtr->rectClient.left,
-wndPtr->rectClient.top );
RedrawWindow32( wndPtr->hwndSelf, &rect, 0, flags );
}
else RedrawWindow32( wndPtr->hwndSelf, NULL, 0, flags );
}
}
}
return TRUE;
}
/***********************************************************************
* RedrawWindow16 (USER.290)
*/
BOOL16 RedrawWindow16( HWND16 hwnd, const RECT16 *rectUpdate,
HRGN16 hrgnUpdate, UINT16 flags )
{
if (rectUpdate)
{
RECT32 r;
CONV_RECT16TO32( rectUpdate, &r );
return (BOOL16)RedrawWindow32( (HWND32)hwnd, &r, hrgnUpdate, flags );
}
return (BOOL16)RedrawWindow32( (HWND32)hwnd, NULL, hrgnUpdate, flags );
}
/***********************************************************************
* UpdateWindow (USER.124) (USER32.566)
*/
void UpdateWindow( HWND32 hwnd )
{
RedrawWindow32( hwnd, NULL, 0, RDW_UPDATENOW | RDW_NOCHILDREN );
}
/***********************************************************************
* InvalidateRgn (USER.126) (USER32.328)
*/
void InvalidateRgn( HWND32 hwnd, HRGN32 hrgn, BOOL32 erase )
{
RedrawWindow32(hwnd, NULL, hrgn, RDW_INVALIDATE | (erase ? RDW_ERASE : 0));
}
/***********************************************************************
* InvalidateRect16 (USER.125)
*/
void InvalidateRect16( HWND16 hwnd, const RECT16 *rect, BOOL16 erase )
{
RedrawWindow16( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
}
/***********************************************************************
* InvalidateRect32 (USER32.327)
*/
void InvalidateRect32( HWND32 hwnd, const RECT32 *rect, BOOL32 erase )
{
RedrawWindow32( hwnd, rect, 0, RDW_INVALIDATE | (erase ? RDW_ERASE : 0) );
}
/***********************************************************************
* ValidateRgn (USER.128) (USER32.571)
*/
void ValidateRgn( HWND32 hwnd, HRGN32 hrgn )
{
RedrawWindow32( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOCHILDREN );
}
/***********************************************************************
* ValidateRect16 (USER.127)
*/
void ValidateRect16( HWND16 hwnd, const RECT16 *rect )
{
RedrawWindow16( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
}
/***********************************************************************
* ValidateRect32 (USER32.570)
*/
void ValidateRect32( HWND32 hwnd, const RECT32 *rect )
{
RedrawWindow32( hwnd, rect, 0, RDW_VALIDATE | RDW_NOCHILDREN );
}
/***********************************************************************
* GetUpdateRect16 (USER.190)
*/
BOOL16 GetUpdateRect16( HWND16 hwnd, LPRECT16 rect, BOOL16 erase )
{
RECT32 r;
BOOL16 ret;
if (!rect) return GetUpdateRect32( hwnd, NULL, erase );
ret = GetUpdateRect32( hwnd, &r, erase );
CONV_RECT32TO16( &r, rect );
return ret;
}
/***********************************************************************
* GetUpdateRect32 (USER32.296)
*/
BOOL32 GetUpdateRect32( HWND32 hwnd, LPRECT32 rect, BOOL32 erase )
{
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return FALSE;
if (rect)
{
if (wndPtr->hrgnUpdate > 1)
{
HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
if (GetUpdateRgn( hwnd, hrgn, erase ) == ERROR) return FALSE;
GetRgnBox32( hrgn, rect );
DeleteObject( hrgn );
}
else SetRectEmpty32( rect );
}
return (wndPtr->hrgnUpdate > 1);
}
/***********************************************************************
* GetUpdateRgn (USER.237) (USER32.297)
*/
INT16 GetUpdateRgn( HWND32 hwnd, HRGN32 hrgn, BOOL32 erase )
{
INT16 retval;
WND * wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return ERROR;
if (wndPtr->hrgnUpdate <= 1)
{
SetRectRgn( hrgn, 0, 0, 0, 0 );
return NULLREGION;
}
retval = CombineRgn( hrgn, wndPtr->hrgnUpdate, 0, RGN_COPY );
if (erase) RedrawWindow32( hwnd, NULL, 0, RDW_ERASENOW | RDW_NOCHILDREN );
return retval;
}
/***********************************************************************
* ExcludeUpdateRgn (USER.238) (USER32.194)
*/
INT16 ExcludeUpdateRgn( HDC32 hdc, HWND32 hwnd )
{
INT16 retval = ERROR;
HRGN hrgn;
WND * wndPtr;
if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return ERROR;
if ((hrgn = CreateRectRgn( 0, 0, 0, 0 )) != 0)
{
retval = CombineRgn( hrgn, InquireVisRgn(hdc),
(wndPtr->hrgnUpdate>1)?wndPtr->hrgnUpdate:0,
(wndPtr->hrgnUpdate>1)?RGN_DIFF:RGN_COPY);
if (retval) SelectVisRgn( hdc, hrgn );
DeleteObject( hrgn );
}
return retval;
}