Moved DCE support to the X11 driver.

This commit is contained in:
Alexandre Julliard 2005-03-25 16:47:04 +00:00
parent dc84b8a4c7
commit 2fb7c8754a
18 changed files with 939 additions and 914 deletions

View file

@ -18,7 +18,6 @@ C_SRCS = \
$(TOPOBJDIR)/windows/class.c \
$(TOPOBJDIR)/windows/clipboard.c \
$(TOPOBJDIR)/windows/cursoricon.c \
$(TOPOBJDIR)/windows/dce.c \
$(TOPOBJDIR)/windows/defdlg.c \
$(TOPOBJDIR)/windows/defwnd.c \
$(TOPOBJDIR)/windows/dialog.c \

View file

@ -32,7 +32,7 @@
#include "winuser.h"
#include "wine/server.h"
#include "win.h"
#include "dce.h"
#include "user_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(win);
@ -416,6 +416,111 @@ BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps )
}
/***********************************************************************
* GetDCEx (USER32.@)
*/
HDC WINAPI GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
{
if (!hwnd) hwnd = GetDesktopWindow();
else hwnd = WIN_GetFullHandle( hwnd );
if (USER_Driver.pGetDCEx) return USER_Driver.pGetDCEx( hwnd, hrgnClip, flags );
return 0;
}
/***********************************************************************
* GetDC (USER32.@)
*
* Get a device context.
*
* RETURNS
* Success: Handle to the device context
* Failure: NULL.
*/
HDC WINAPI GetDC( HWND hwnd )
{
if (!hwnd) return GetDCEx( 0, 0, DCX_CACHE | DCX_WINDOW );
return GetDCEx( hwnd, 0, DCX_USESTYLE );
}
/***********************************************************************
* GetWindowDC (USER32.@)
*/
HDC WINAPI GetWindowDC( HWND hwnd )
{
return GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW );
}
/***********************************************************************
* ReleaseDC (USER32.@)
*
* Release a device context.
*
* RETURNS
* Success: Non-zero. Resources used by hdc are released.
* Failure: 0.
*/
INT WINAPI ReleaseDC( HWND hwnd, HDC hdc )
{
if (USER_Driver.pReleaseDC) return USER_Driver.pReleaseDC( hwnd, hdc );
return 0;
}
/**********************************************************************
* WindowFromDC (USER32.@)
*/
HWND WINAPI WindowFromDC( HDC hDC )
{
if (USER_Driver.pWindowFromDC) return USER_Driver.pWindowFromDC( hDC );
return 0;
}
/***********************************************************************
* LockWindowUpdate (USER32.@)
*/
BOOL WINAPI LockWindowUpdate( HWND hwnd )
{
static HWND lockedWnd;
/* This function is fully implemented by the following patch:
*
* http://www.winehq.org/hypermail/wine-patches/2004/01/0142.html
*
* but in order to work properly, it needs the ability to invalidate
* DCEs in other processes when the lock window is changed, which
* isn't possible yet.
* -mike
*/
FIXME("(%p), partial stub!\n",hwnd);
USER_Lock();
if (lockedWnd)
{
if (!hwnd)
{
/* Unlock lockedWnd */
/* FIXME: Do something */
}
else
{
/* Attempted to lock a second window */
/* Return FALSE and do nothing */
USER_Unlock();
return FALSE;
}
}
lockedWnd = hwnd;
USER_Unlock();
return TRUE;
}
/***********************************************************************
* RedrawWindow (USER32.@)
*/

View file

@ -811,6 +811,16 @@ BOOL16 WINAPI IsMenu16( HMENU16 hmenu )
}
/***********************************************************************
* DCHook (USER.362)
*/
BOOL16 WINAPI DCHook16( HDC16 hdc, WORD code, DWORD data, LPARAM lParam )
{
FIXME( "hDC = %x, %i: stub\n", hdc, code );
return FALSE;
}
/**********************************************************************
* SetMenuContextHelpId (USER.384)
*/

View file

@ -725,7 +725,6 @@
################################################################
# Wine dll separation hacks, these will go away, don't use them
#
@ cdecl DCE_InvalidateDCE(long ptr)
@ cdecl HOOK_CallHooks(long long long long long)
@ cdecl USER_Unlock()
@ cdecl WINPOS_ActivateOtherWindow(long)

View file

@ -116,7 +116,7 @@ static BOOL load_driver(void)
GET_USER_FUNC(EnumDisplaySettingsExW);
GET_USER_FUNC(CreateWindow);
GET_USER_FUNC(DestroyWindow);
GET_USER_FUNC(GetDC);
GET_USER_FUNC(GetDCEx);
GET_USER_FUNC(MsgWaitForMultipleObjectsEx);
GET_USER_FUNC(ReleaseDC);
GET_USER_FUNC(ScrollDC);
@ -129,6 +129,7 @@ static BOOL load_driver(void)
GET_USER_FUNC(SetWindowText);
GET_USER_FUNC(ShowWindow);
GET_USER_FUNC(SysCommandSizeMove);
GET_USER_FUNC(WindowFromDC);
GET_USER_FUNC(WindowMessage);
return TRUE;

View file

@ -100,9 +100,9 @@ typedef struct tagUSER_DRIVER {
/* windowing functions */
BOOL (*pCreateWindow)(HWND,CREATESTRUCTA*,BOOL);
BOOL (*pDestroyWindow)(HWND);
BOOL (*pGetDC)(HWND,HDC,HRGN,DWORD);
HDC (*pGetDCEx)(HWND,HRGN,DWORD);
DWORD (*pMsgWaitForMultipleObjectsEx)(DWORD,const HANDLE*,DWORD,DWORD,DWORD);
void (*pReleaseDC)(HWND,HDC);
BOOL (*pReleaseDC)(HWND,HDC);
BOOL (*pScrollDC)(HDC, INT, INT, const RECT *, const RECT *, HRGN, LPRECT);
void (*pSetFocus)(HWND);
HWND (*pSetParent)(HWND,HWND);
@ -113,6 +113,7 @@ typedef struct tagUSER_DRIVER {
BOOL (*pSetWindowText)(HWND,LPCWSTR);
BOOL (*pShowWindow)(HWND,INT);
void (*pSysCommandSizeMove)(HWND,WPARAM);
HWND (*pWindowFromDC)(HDC);
LRESULT (*pWindowMessage)(HWND,UINT,WPARAM,LPARAM);
} USER_DRIVER;

View file

@ -14,6 +14,7 @@ C_SRCS = \
clipboard.c \
clipping.c \
codepage.c \
dce.c \
desktop.c \
dga2.c \
dib.c \

789
dlls/x11drv/dce.c Normal file
View file

@ -0,0 +1,789 @@
/*
* USER DCE functions
*
* Copyright 1993, 2005 Alexandre Julliard
* Copyright 1996, 1997 Alex Korobka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Note: Visible regions of CS_OWNDC/CS_CLASSDC window DCs
* have to be updated dynamically.
*
* Internal DCX flags:
*
* DCX_WINDOWPAINT - BeginPaint() is in effect
*/
#include "config.h"
#include <assert.h>
#include "win.h"
#include "windef.h"
#include "wingdi.h"
#include "wownt32.h"
#include "ntstatus.h"
#include "x11drv.h"
#include "wine/winbase16.h"
#include "wine/wingdi16.h"
#include "wine/server.h"
#include "wine/list.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dc);
struct dce
{
struct list entry; /* entry in global DCE list */
HDC hdc;
HWND hwnd;
HRGN clip_rgn;
DWORD flags;
int empty : 1; /* DCE is uninitialized */
int inuse : 1; /* DCE is in use */
int dirty : 1; /* ReleaseDC should wipe instead of caching */
void *class_ptr; /* ptr to identify window class for class DCEs */
ULONG count; /* reference count for class DCEs */
};
static struct list dce_list = LIST_INIT(dce_list);
static void delete_clip_rgn( struct dce * );
static INT release_dc( struct dce * );
static BOOL16 CALLBACK dc_hook( HDC16 hDC, WORD code, DWORD data, LPARAM lParam );
static CRITICAL_SECTION dce_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &dce_section,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { 0, (DWORD)(__FILE__ ": dce_section") }
};
static CRITICAL_SECTION dce_section = { &critsect_debug, -1, 0, 0, 0, 0 };
static const WCHAR displayW[] = { 'D','I','S','P','L','A','Y',0 };
/***********************************************************************
* dump_cache
*/
static void dump_cache(void)
{
struct dce *dce;
EnterCriticalSection( &dce_section );
LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry )
{
TRACE("%p: hwnd %p dcx %08lx %s %s\n",
dce, dce->hwnd, dce->flags,
(dce->flags & DCX_CACHE) ? "Cache" : "Owned",
dce->inuse ? "InUse" : "" );
}
LeaveCriticalSection( &dce_section );
}
/***********************************************************************
* get_server_visible_region
*/
static HRGN get_server_visible_region( HWND hwnd, UINT flags )
{
RGNDATA *data;
NTSTATUS status;
HRGN ret = 0;
size_t size = 256;
do
{
if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) return 0;
SERVER_START_REQ( get_visible_region )
{
req->window = hwnd;
req->flags = flags;
wine_server_set_reply( req, data->Buffer, size );
if (!(status = wine_server_call( req )))
{
size_t reply_size = wine_server_reply_size( reply );
data->rdh.dwSize = sizeof(data->rdh);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = reply_size / sizeof(RECT);
data->rdh.nRgnSize = reply_size;
ret = ExtCreateRegion( NULL, size, data );
}
else size = reply->total_size;
}
SERVER_END_REQ;
HeapFree( GetProcessHeap(), 0, data );
} while (status == STATUS_BUFFER_OVERFLOW);
if (status) SetLastError( RtlNtStatusToDosError(status) );
return ret;
}
/***********************************************************************
* get_top_clipping_window
*
* Get the top window to clip against (i.e. the top parent that has
* an associated X window).
*/
static HWND get_top_clipping_window( HWND hwnd )
{
HWND ret = GetAncestor( hwnd, GA_ROOT );
if (!ret) ret = GetDesktopWindow();
return ret;
}
/***********************************************************************
* set_drawable
*
* Set the drawable, origin and dimensions for the DC associated to
* a given window.
*/
static BOOL set_drawable( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
{
HWND top = get_top_clipping_window( hwnd );
struct x11drv_escape_set_drawable escape;
struct x11drv_win_data *data;
escape.mode = IncludeInferiors;
/* don't clip siblings if using parent clip region */
if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
if (top != hwnd || !(data = X11DRV_get_win_data( hwnd )))
{
POINT client_offset;
if (flags & DCX_WINDOW)
{
RECT rect;
GetWindowRect( hwnd, &rect );
escape.org.x = rect.left;
escape.org.y = rect.top;
MapWindowPoints( 0, top, &escape.org, 1 );
escape.drawable_org.x = rect.left - escape.org.x;
escape.drawable_org.y = rect.top - escape.org.y;
}
else
{
escape.org.x = escape.org.y = 0;
escape.drawable_org.x = escape.drawable_org.y = 0;
MapWindowPoints( hwnd, top, &escape.org, 1 );
MapWindowPoints( top, 0, &escape.drawable_org, 1 );
}
/* now make origins relative to the X window and not the client area */
client_offset = X11DRV_get_client_area_offset( top );
escape.org.x += client_offset.x;
escape.org.y += client_offset.y;
escape.drawable_org.x -= client_offset.x;
escape.drawable_org.y -= client_offset.y;
escape.drawable = X11DRV_get_whole_window( top );
}
else
{
if (IsIconic( hwnd ))
{
escape.drawable = data->icon_window ? data->icon_window : data->whole_window;
escape.org.x = 0;
escape.org.y = 0;
escape.drawable_org = escape.org;
MapWindowPoints( hwnd, 0, &escape.drawable_org, 1 );
}
else
{
escape.drawable = data->whole_window;
escape.drawable_org.x = data->whole_rect.left;
escape.drawable_org.y = data->whole_rect.top;
if (flags & DCX_WINDOW)
{
escape.org.x = data->window_rect.left - data->whole_rect.left;
escape.org.y = data->window_rect.top - data->whole_rect.top;
}
else
{
escape.org.x = data->client_rect.left;
escape.org.y = data->client_rect.top;
}
}
}
escape.code = X11DRV_SET_DRAWABLE;
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) ||
SetHookFlags16( HDC_16(hdc), DCHF_VALIDATEVISRGN )) /* DC was dirty */
{
/* need to recompute the visible region */
HRGN visRgn = get_server_visible_region( hwnd, flags );
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
CombineRgn( visRgn, visRgn, hrgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
SelectVisRgn16( HDC_16(hdc), HRGN_16(visRgn) );
DeleteObject( visRgn );
}
return TRUE;
}
/***********************************************************************
* release_drawable
*/
static void release_drawable( HWND hwnd, HDC hdc )
{
struct x11drv_escape_set_drawable escape;
escape.code = X11DRV_SET_DRAWABLE;
escape.drawable = root_window;
escape.mode = IncludeInferiors;
escape.org.x = escape.org.y = 0;
escape.drawable_org.x = escape.drawable_org.y = 0;
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
}
/***********************************************************************
* alloc_cache_dce
*
* Allocate a new cache DCE.
*/
static struct dce *alloc_cache_dce(void)
{
struct dce *dce;
if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(*dce) ))) return NULL;
if (!(dce->hdc = CreateDCW( displayW, NULL, NULL, NULL )))
{
HeapFree( GetProcessHeap(), 0, dce );
return 0;
}
SaveDC( dce->hdc );
/* store DCE handle in DC hook data field */
SetDCHook( dce->hdc, dc_hook, (DWORD)dce );
dce->hwnd = 0;
dce->clip_rgn = 0;
dce->flags = DCX_CACHE;
dce->empty = 1;
dce->inuse = 0;
dce->dirty = 0;
dce->class_ptr = NULL;
dce->count = 0;
EnterCriticalSection( &dce_section );
list_add_head( &dce_list, &dce->entry );
LeaveCriticalSection( &dce_section );
return dce;
}
/***********************************************************************
* alloc_window_dce
*
* Allocate a DCE for a newly created window if necessary.
*/
void alloc_window_dce( struct x11drv_win_data *data )
{
struct dce *dce;
void *class_ptr = NULL;
LONG style = GetClassLongW( data->hwnd, GCL_STYLE );
if (!(style & (CS_CLASSDC|CS_OWNDC))) return; /* nothing to do */
if (!(style & CS_OWNDC)) /* class dc */
{
/* hack: get the class pointer from the window structure */
WND *win = WIN_GetPtr( data->hwnd );
class_ptr = win->class;
WIN_ReleasePtr( win );
EnterCriticalSection( &dce_section );
LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry )
{
if (dce->class_ptr == class_ptr)
{
dce->count++;
data->dce = dce;
LeaveCriticalSection( &dce_section );
return;
}
}
LeaveCriticalSection( &dce_section );
}
/* now allocate a new one */
if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(*dce) ))) return;
if (!(dce->hdc = CreateDCW( displayW, NULL, NULL, NULL )))
{
HeapFree( GetProcessHeap(), 0, dce );
return;
}
SaveDC( dce->hdc );
/* store DCE handle in DC hook data field */
SetDCHook( dce->hdc, dc_hook, (DWORD)dce );
dce->hwnd = data->hwnd;
dce->clip_rgn = 0;
dce->flags = 0;
dce->empty = 0;
dce->inuse = 1;
dce->dirty = 0;
dce->class_ptr = class_ptr;
dce->count = 1;
if (style & CS_OWNDC)
{
LONG win_style = GetWindowLongW( data->hwnd, GWL_STYLE );
if (win_style & WS_CLIPCHILDREN) dce->flags |= DCX_CLIPCHILDREN;
if (win_style & WS_CLIPSIBLINGS) dce->flags |= DCX_CLIPSIBLINGS;
}
SetHookFlags16( HDC_16(dce->hdc), DCHF_INVALIDATEVISRGN );
EnterCriticalSection( &dce_section );
list_add_tail( &dce_list, &dce->entry );
LeaveCriticalSection( &dce_section );
data->dce = dce;
}
/***********************************************************************
* free_window_dce
*
* Free a class or window DCE.
*/
void free_window_dce( struct x11drv_win_data *data )
{
struct dce *dce = data->dce;
if (dce)
{
EnterCriticalSection( &dce_section );
if (!--dce->count)
{
list_remove( &dce->entry );
SetDCHook(dce->hdc, NULL, 0L);
DeleteDC( dce->hdc );
if (dce->clip_rgn) DeleteObject( dce->clip_rgn );
HeapFree( GetProcessHeap(), 0, dce );
}
else if (dce->hwnd == data->hwnd)
{
if (dce->flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN))
{
release_drawable( dce->hwnd, dce->hdc );
delete_clip_rgn( dce );
dce->hwnd = 0;
}
}
LeaveCriticalSection( &dce_section );
data->dce = NULL;
}
/* now check for cache DCEs */
EnterCriticalSection( &dce_section );
LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry )
{
if (dce->hwnd != data->hwnd) continue;
if (!(dce->flags & DCX_CACHE)) continue;
if (dce->inuse) /* shared cache DCE */
{
WARN( "GetDC() without ReleaseDC() for window %p\n", data->hwnd );
release_dc( dce );
}
if (dce->hwnd) release_drawable( dce->hwnd, dce->hdc );
dce->hwnd = 0;
dce->flags = DCX_CACHE;
dce->inuse = 0;
dce->empty = 1;
dce->dirty = 0;
}
LeaveCriticalSection( &dce_section );
}
/***********************************************************************
* delete_clip_rgn
*/
static void delete_clip_rgn( struct dce *dce )
{
dce->flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);
if (dce->clip_rgn) DeleteObject( dce->clip_rgn );
dce->clip_rgn = 0;
/* make it dirty so that the vis rgn gets recomputed next time */
dce->dirty = 1;
SetHookFlags16( HDC_16(dce->hdc), DCHF_INVALIDATEVISRGN );
}
/***********************************************************************
* release_dc
*/
static BOOL release_dc( struct dce *dce )
{
if (dce->empty) return FALSE;
if (!dce->inuse) return FALSE;
/* restore previous visible region */
if ((dce->flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
(dce->flags & (DCX_CACHE | DCX_WINDOWPAINT)) )
delete_clip_rgn( dce );
if (dce->flags & DCX_CACHE)
{
/* make the DC clean so that RestoreDC doesn't try to update the vis rgn */
SetHookFlags16( HDC_16(dce->hdc), DCHF_VALIDATEVISRGN );
RestoreDC( dce->hdc, 1 ); /* initial save level is always 1 */
SaveDC( dce->hdc ); /* save the state again for next time */
dce->inuse = 0;
if (dce->dirty)
{
/* don't keep around invalidated entries
* because RestoreDC() disables hVisRgn updates
* by removing dirty bit. */
if (dce->hwnd) release_drawable( dce->hwnd, dce->hdc );
dce->hwnd = 0;
dce->flags = DCX_CACHE;
dce->empty = 1;
dce->dirty = 0;
}
}
return TRUE;
}
/***********************************************************************
* invalidate_dce
*
* It is called from SetWindowPos() - we have to
* mark as dirty all busy DCEs for windows that have pWnd->parent as
* an ancestor and whose client rect intersects with specified update
* rectangle. In addition, pWnd->parent DCEs may need to be updated if
* DCX_CLIPCHILDREN flag is set.
*/
void invalidate_dce( HWND hwnd, const RECT *rect )
{
HWND hwndScope = GetAncestor( hwnd, GA_PARENT );
if( hwndScope )
{
struct dce *dce;
TRACE("scope hwnd = %p %s\n", hwndScope, wine_dbgstr_rect(rect) );
if (TRACE_ON(dc)) dump_cache();
/* walk all DCEs and fixup non-empty entries */
LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry )
{
if (dce->empty) continue;
if ((dce->hwnd == hwndScope) && !(dce->flags & DCX_CLIPCHILDREN))
continue; /* child window positions don't bother us */
/* check if DCE window is within the z-order scope */
if (hwndScope == dce->hwnd || IsChild( hwndScope, dce->hwnd ))
{
if (hwnd != dce->hwnd)
{
/* check if the window rectangle intersects this DCE window */
RECT tmp;
GetWindowRect( dce->hwnd, &tmp );
MapWindowPoints( 0, hwndScope, (POINT *)&tmp, 2 );
if (!IntersectRect( &tmp, &tmp, rect )) continue;
}
if (!dce->inuse)
{
/* Don't bother with visible regions of unused DCEs */
TRACE("\tpurged %p dce [%p]\n", dce, dce->hwnd);
if (dce->hwnd) release_drawable( dce->hwnd, dce->hdc );
dce->hwnd = 0;
dce->flags &= DCX_CACHE;
dce->empty = 1;
dce->dirty = 0;
}
else
{
/* Set dirty bits in the hDC and DCE structs */
TRACE("\tfixed up %p dce [%p]\n", dce, dce->hwnd);
dce->dirty = 1;
SetHookFlags16( HDC_16(dce->hdc), DCHF_INVALIDATEVISRGN );
}
}
} /* dce list */
}
}
/***********************************************************************
* X11DRV_GetDCEx (X11DRV.@)
*
* Unimplemented flags: DCX_LOCKWINDOWUPDATE
*/
HDC X11DRV_GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
{
struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
struct dce *dce;
HDC hdc = 0;
DWORD dcxFlags = 0;
BOOL bUpdateVisRgn = TRUE;
HWND parent;
LONG window_style = GetWindowLongW( hwnd, GWL_STYLE );
TRACE("hwnd %p, hrgnClip %p, flags %08lx\n", hwnd, hrgnClip, flags);
/* fixup flags */
if (flags & (DCX_WINDOW | DCX_PARENTCLIP)) flags |= DCX_CACHE;
if (flags & DCX_USESTYLE)
{
flags &= ~(DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
if (window_style & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
if (!(flags & DCX_WINDOW))
{
if (GetClassLongW( hwnd, GCL_STYLE ) & CS_PARENTDC) flags |= DCX_PARENTCLIP;
if (window_style & WS_CLIPCHILDREN && !(window_style & WS_MINIMIZE))
flags |= DCX_CLIPCHILDREN;
if (!data || !data->dce) flags |= DCX_CACHE;
}
}
if (flags & DCX_WINDOW) flags &= ~DCX_CLIPCHILDREN;
parent = GetAncestor( hwnd, GA_PARENT );
if (!parent || (parent == GetDesktopWindow()))
flags = (flags & ~DCX_PARENTCLIP) | DCX_CLIPSIBLINGS;
/* it seems parent clip is ignored when clipping siblings or children */
if (flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) flags &= ~DCX_PARENTCLIP;
if( flags & DCX_PARENTCLIP )
{
LONG parent_style = GetWindowLongW( parent, GWL_STYLE );
if( (window_style & WS_VISIBLE) && (parent_style & WS_VISIBLE) )
{
flags &= ~DCX_CLIPCHILDREN;
if (parent_style & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
}
}
if (!(flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN))) hrgnClip = 0;
/* find a suitable DCE */
EnterCriticalSection( &dce_section );
dcxFlags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
DCX_CACHE | DCX_WINDOW);
if (flags & DCX_CACHE)
{
struct dce *dceEmpty = NULL, *dceUnused = NULL;
/* Strategy: First, we attempt to find a non-empty but unused DCE with
* compatible flags. Next, we look for an empty entry. If the cache is
* full we have to purge one of the unused entries.
*/
LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry )
{
if ((dce->flags & DCX_CACHE) && !dce->inuse)
{
dceUnused = dce;
if (dce->empty) dceEmpty = dce;
else if ((dce->hwnd == hwnd) &&
((dce->flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)) == dcxFlags))
{
TRACE("\tfound valid %p dce [%p], flags %08lx\n",
dce, hwnd, dcxFlags );
bUpdateVisRgn = FALSE;
break;
}
}
}
if (&dce->entry == &dce_list) /* nothing found */
dce = dceEmpty ? dceEmpty : dceUnused;
/* if there's no dce empty or unused, allocate a new one */
if (!dce) dce = alloc_cache_dce();
}
else
{
dce = data->dce;
if (dce && dce->hwnd == hwnd)
{
TRACE("\tskipping hVisRgn update\n");
bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
}
}
if (!dce)
{
hdc = 0;
goto END;
}
if (((flags ^ dce->flags) & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
(dce->clip_rgn != hrgnClip))
{
/* if the extra clip region has changed, get rid of the old one */
delete_clip_rgn( dce );
}
dce->hwnd = hwnd;
dce->clip_rgn = hrgnClip;
dce->flags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
DCX_CACHE | DCX_WINDOW | DCX_WINDOWPAINT |
DCX_INTERSECTRGN | DCX_EXCLUDERGN);
dce->empty = 0;
dce->inuse = 1;
dce->dirty = 0;
hdc = dce->hdc;
if (bUpdateVisRgn) SetHookFlags16( HDC_16(hdc), DCHF_INVALIDATEVISRGN ); /* force update */
if (!set_drawable( hwnd, hdc, hrgnClip, flags )) hdc = 0;
TRACE("(%p,%p,0x%lx): returning %p\n", hwnd, hrgnClip, flags, hdc);
END:
LeaveCriticalSection( &dce_section );
return hdc;
}
/***********************************************************************
* X11DRV_ReleaseDC (X11DRV.@)
*/
BOOL X11DRV_ReleaseDC( HWND hwnd, HDC hdc )
{
struct dce * dce;
BOOL ret = FALSE;
TRACE("%p %p\n", hwnd, hdc );
EnterCriticalSection( &dce_section );
LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry )
{
if (dce->hdc == hdc)
{
if (dce->inuse) ret = release_dc( dce );
break;
}
}
LeaveCriticalSection( &dce_section );
return ret;
}
/***********************************************************************
* dc_hook
*
* See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
*/
static BOOL16 CALLBACK dc_hook( HDC16 hDC, WORD code, DWORD data, LPARAM lParam )
{
BOOL retv = TRUE;
struct dce *dce = (struct dce *)data;
TRACE("hDC = %04x, %i\n", hDC, code);
if (!dce) return 0;
assert( HDC_16(dce->hdc) == hDC );
switch( code )
{
case DCHC_INVALIDVISRGN:
/* GDI code calls this when it detects that the
* DC is dirty (usually after SetHookFlags()). This
* means that we have to recompute the visible region.
*/
if (dce->inuse)
{
/* Dirty bit has been cleared by caller, set it again so that
* pGetDC recomputes the visible region. */
SetHookFlags16( hDC, DCHF_INVALIDATEVISRGN );
set_drawable( dce->hwnd, dce->hdc, dce->clip_rgn, dce->flags );
}
else /* non-fatal but shouldn't happen */
WARN("DC is not in use!\n");
break;
case DCHC_DELETEDC:
/*
* Windows will not let you delete a DC that is busy
* (between GetDC and ReleaseDC)
*/
if (dce->inuse)
{
WARN("Application trying to delete a busy DC\n");
retv = FALSE;
}
else
{
EnterCriticalSection( &dce_section );
list_remove( &dce->entry );
LeaveCriticalSection( &dce_section );
if (dce->clip_rgn) DeleteObject( dce->clip_rgn );
HeapFree( GetProcessHeap(), 0, dce );
}
break;
}
return retv;
}
/**********************************************************************
* WindowFromDC (X11DRV.@)
*/
HWND X11DRV_WindowFromDC( HDC hDC )
{
struct dce *dce;
HWND hwnd = 0;
EnterCriticalSection( &dce_section );
LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry )
{
if (dce->hdc == hDC)
{
hwnd = dce->hwnd;
break;
}
}
LeaveCriticalSection( &dce_section );
return hwnd;
}

View file

@ -845,6 +845,7 @@ BOOL X11DRV_DestroyWindow( HWND hwnd )
if (!(data = X11DRV_get_win_data( hwnd ))) return TRUE;
free_window_dce( data );
destroy_whole_window( display, data );
destroy_icon_window( display, data );
@ -902,6 +903,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
data->icon_window = 0;
data->xic = 0;
data->managed = FALSE;
data->dce = NULL;
data->hWMIconBitmap = 0;
data->hWMIconMask = 0;
@ -927,8 +929,11 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
if (!create_whole_window( display, data, cs->style )) goto failed;
}
/* get class or window DC if needed */
alloc_window_dce( data );
/* Call the WH_CBT hook */
/* the window style passed to the hook must be the real window style,
* rather than just the window style that the caller to CreateWindowEx
* passed in, so we have to copy the original CREATESTRUCT and get the

View file

@ -40,7 +40,6 @@
#include "x11drv.h"
#include "win.h"
#include "winpos.h"
#include "dce.h"
#include "wine/server.h"
#include "wine/debug.h"
@ -82,58 +81,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
/***********************************************************************
* get_server_visible_region
*/
static HRGN get_server_visible_region( HWND hwnd, UINT flags )
{
RGNDATA *data;
NTSTATUS status;
HRGN ret = 0;
size_t size = 256;
do
{
if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ))) return 0;
SERVER_START_REQ( get_visible_region )
{
req->window = hwnd;
req->flags = flags;
wine_server_set_reply( req, data->Buffer, size );
if (!(status = wine_server_call( req )))
{
size_t reply_size = wine_server_reply_size( reply );
data->rdh.dwSize = sizeof(data->rdh);
data->rdh.iType = RDH_RECTANGLES;
data->rdh.nCount = reply_size / sizeof(RECT);
data->rdh.nRgnSize = reply_size;
ret = ExtCreateRegion( NULL, size, data );
}
else size = reply->total_size;
}
SERVER_END_REQ;
HeapFree( GetProcessHeap(), 0, data );
} while (status == STATUS_BUFFER_OVERFLOW);
if (status) SetLastError( RtlNtStatusToDosError(status) );
return ret;
}
/***********************************************************************
* get_top_clipping_window
*
* Get the top window to clip against (i.e. the top parent that has
* an associated X window).
*/
static HWND get_top_clipping_window( HWND hwnd )
{
HWND ret = GetAncestor( hwnd, GA_ROOT );
if (!ret) ret = GetDesktopWindow();
return ret;
}
/***********************************************************************
* X11DRV_Expose
*/
@ -176,116 +123,6 @@ void X11DRV_Expose( HWND hwnd, XEvent *xev )
}
/***********************************************************************
* GetDC (X11DRV.@)
*
* Set the drawable, origin and dimensions for the DC associated to
* a given window.
*/
BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
{
HWND top = get_top_clipping_window( hwnd );
struct x11drv_escape_set_drawable escape;
struct x11drv_win_data *data;
escape.mode = IncludeInferiors;
/* don't clip siblings if using parent clip region */
if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
if (top != hwnd || !(data = X11DRV_get_win_data( hwnd )))
{
POINT client_offset;
if (flags & DCX_WINDOW)
{
RECT rect;
GetWindowRect( hwnd, &rect );
escape.org.x = rect.left;
escape.org.y = rect.top;
MapWindowPoints( 0, top, &escape.org, 1 );
escape.drawable_org.x = rect.left - escape.org.x;
escape.drawable_org.y = rect.top - escape.org.y;
}
else
{
escape.org.x = escape.org.y = 0;
escape.drawable_org.x = escape.drawable_org.y = 0;
MapWindowPoints( hwnd, top, &escape.org, 1 );
MapWindowPoints( top, 0, &escape.drawable_org, 1 );
}
/* now make origins relative to the X window and not the client area */
client_offset = X11DRV_get_client_area_offset( top );
escape.org.x += client_offset.x;
escape.org.y += client_offset.y;
escape.drawable_org.x -= client_offset.x;
escape.drawable_org.y -= client_offset.y;
escape.drawable = X11DRV_get_whole_window( top );
}
else
{
if (IsIconic( hwnd ))
{
escape.drawable = data->icon_window ? data->icon_window : data->whole_window;
escape.org.x = 0;
escape.org.y = 0;
escape.drawable_org = escape.org;
MapWindowPoints( hwnd, 0, &escape.drawable_org, 1 );
}
else
{
escape.drawable = data->whole_window;
escape.drawable_org.x = data->whole_rect.left;
escape.drawable_org.y = data->whole_rect.top;
if (flags & DCX_WINDOW)
{
escape.org.x = data->window_rect.left - data->whole_rect.left;
escape.org.y = data->window_rect.top - data->whole_rect.top;
}
else
{
escape.org.x = data->client_rect.left;
escape.org.y = data->client_rect.top;
}
}
}
escape.code = X11DRV_SET_DRAWABLE;
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) ||
SetHookFlags16( HDC_16(hdc), DCHF_VALIDATEVISRGN )) /* DC was dirty */
{
/* need to recompute the visible region */
HRGN visRgn = get_server_visible_region( hwnd, flags );
if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
CombineRgn( visRgn, visRgn, hrgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
SelectVisRgn16( HDC_16(hdc), HRGN_16(visRgn) );
DeleteObject( visRgn );
}
return TRUE;
}
/***********************************************************************
* ReleaseDC (X11DRV.@)
*/
void X11DRV_ReleaseDC( HWND hwnd, HDC hdc )
{
struct x11drv_escape_set_drawable escape;
escape.code = X11DRV_SET_DRAWABLE;
escape.drawable = root_window;
escape.mode = IncludeInferiors;
escape.org.x = escape.org.y = 0;
escape.drawable_org.x = escape.drawable_org.y = 0;
ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL );
}
/***********************************************************************
* SWP_DoWinPosChanging
*/
@ -659,7 +496,7 @@ void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style )
}
/* we don't unmap windows, that causes trouble with the window manager */
}
DCE_InvalidateDCE( hwnd, &data->window_rect );
invalidate_dce( hwnd, &data->window_rect );
}
if (changed & WS_DISABLED)
@ -764,7 +601,7 @@ BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow
{
RECT rect;
UnionRect( &rect, rectWindow, &win->rectWindow );
DCE_InvalidateDCE( hwnd, &rect );
invalidate_dce( hwnd, &rect );
}
win->rectWindow = *rectWindow;
@ -1238,7 +1075,7 @@ void X11DRV_MapNotify( HWND hwnd, XEvent *event )
rect.bottom = y + height;
X11DRV_X_to_window_rect( data, &rect );
DCE_InvalidateDCE( hwnd, &data->window_rect );
invalidate_dce( hwnd, &data->window_rect );
if (win->flags & WIN_RESTORE_MAX) style |= WS_MAXIMIZE;
WIN_SetStyle( hwnd, style, WS_MINIMIZE );

View file

@ -627,16 +627,17 @@ enum x11drv_window_messages
/* x11drv private window data */
struct x11drv_win_data
{
HWND hwnd; /* hwnd that this private data belongs to */
Window whole_window; /* X window for the complete window */
Window icon_window; /* X window for the icon */
RECT window_rect; /* USER window rectangle relative to parent */
RECT whole_rect; /* X window rectangle for the whole window relative to parent */
RECT client_rect; /* client area relative to whole window */
XIC xic; /* X input context */
BOOL managed; /* is window managed? */
HBITMAP hWMIconBitmap;
HBITMAP hWMIconMask;
HWND hwnd; /* hwnd that this private data belongs to */
Window whole_window; /* X window for the complete window */
Window icon_window; /* X window for the icon */
RECT window_rect; /* USER window rectangle relative to parent */
RECT whole_rect; /* X window rectangle for the whole window relative to parent */
RECT client_rect; /* client area relative to whole window */
XIC xic; /* X input context */
BOOL managed; /* is window managed? */
struct dce *dce; /* DCE for CS_OWNDC or CS_CLASSDC windows */
HBITMAP hWMIconBitmap;
HBITMAP hWMIconMask;
};
extern struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd );
@ -645,6 +646,9 @@ extern Window X11DRV_get_whole_window( HWND hwnd );
extern BOOL X11DRV_is_window_rect_mapped( const RECT *rect );
extern XIC X11DRV_get_ic( HWND hwnd );
extern void alloc_window_dce( struct x11drv_win_data *data );
extern void free_window_dce( struct x11drv_win_data *data );
extern void invalidate_dce( HWND hwnd, const RECT *rect );
/* X context to associate a hwnd to an X window */
extern XContext winContext;

View file

@ -92,7 +92,7 @@
@ cdecl EnumClipboardFormats(long) X11DRV_EnumClipboardFormats
@ cdecl GetClipboardData(long ptr ptr) X11DRV_GetClipboardData
@ cdecl GetClipboardFormatName(long str long) X11DRV_GetClipboardFormatName
@ cdecl GetDC(long long long long) X11DRV_GetDC
@ cdecl GetDCEx(long long long) X11DRV_GetDCEx
@ cdecl IsClipboardFormatAvailable(long) X11DRV_IsClipboardFormatAvailable
@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) X11DRV_MsgWaitForMultipleObjectsEx
@ cdecl RegisterClipboardFormat(str) X11DRV_RegisterClipboardFormat
@ -109,6 +109,7 @@
@ cdecl SetWindowText(long wstr) X11DRV_SetWindowText
@ cdecl ShowWindow(long long) X11DRV_ShowWindow
@ cdecl SysCommandSizeMove(long long) X11DRV_SysCommandSizeMove
@ cdecl WindowFromDC(long) X11DRV_WindowFromDC
@ cdecl WindowMessage(long long long long) X11DRV_WindowMessage
# WinTab32

View file

@ -1,46 +0,0 @@
/*
* USER DCE definitions
*
* Copyright 1993 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __WINE_DCE_H
#define __WINE_DCE_H
#include <windef.h>
/* internal DCX flags */
#define DCX_DCEEMPTY 0x00000800
#define DCX_DCEBUSY 0x00001000
#define DCX_DCEDIRTY 0x00002000
#define DCX_WINDOWPAINT 0x00020000
typedef enum
{
DCE_CACHE_DC, /* This is a cached DC (allocated by USER) */
DCE_CLASS_DC, /* This is a class DC (style CS_CLASSDC) */
DCE_WINDOW_DC /* This is a window DC (style CS_OWNDC) */
} DCE_TYPE;
struct tagDCE;
extern struct tagDCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type );
extern void DCE_FreeDCE( struct tagDCE *dce );
extern void DCE_FreeWindowDCE( HWND );
extern BOOL DCE_InvalidateDCE( HWND, const RECT* );
#endif /* __WINE_DCE_H */

View file

@ -31,7 +31,6 @@
#define WND_MAGIC 0x444e4957 /* 'WIND' */
struct tagCLASS;
struct tagDCE;
typedef struct tagWND
{
@ -48,7 +47,6 @@ typedef struct tagWND
LPWSTR text; /* Window text */
void *pVScroll; /* Vertical scroll-bar info */
void *pHScroll; /* Horizontal scroll-bar info */
struct tagDCE *dce; /* Window DCE (if CS_OWNDC or CS_CLASSDC) */
DWORD dwStyle; /* Window style (from CreateWindow) */
DWORD dwExStyle; /* Extended style (from CreateWindowEx) */
DWORD clsStyle; /* Class style at window creation */
@ -108,4 +106,7 @@ inline static void WIN_ReleasePtr( WND *ptr )
extern LRESULT HOOK_CallHooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL unicode );
/* internal GetDC flag (FIXME) */
#define DCX_WINDOWPAINT 0x00020000
#endif /* __WINE_WIN_H */

View file

@ -36,7 +36,6 @@
#include "win.h"
#include "user_private.h"
#include "controls.h"
#include "dce.h"
#include "winproc.h"
#include "wine/server.h"
#include "wine/list.h"
@ -55,7 +54,6 @@ typedef struct tagCLASS
INT cbWndExtra; /* Window extra bytes */
LPWSTR menuName; /* Default menu name (Unicode followed by ASCII) */
SEGPTR segMenuName; /* Default menu name as SEGPTR */
struct tagDCE *dce; /* Class DCE (if CS_CLASSDC) */
HINSTANCE hInstance; /* Module that created the task */
HICON hIcon; /* Default icon */
HICON hIconSm; /* Default small icon */
@ -292,7 +290,6 @@ static void CLASS_FreeClass( CLASS *classPtr )
USER_Lock();
list_remove( &classPtr->entry );
if (classPtr->dce) DCE_FreeDCE( classPtr->dce );
if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
DeleteObject( classPtr->hbrBackground );
UnMapLS( classPtr->segMenuName );
@ -421,7 +418,6 @@ static CLASS *CLASS_RegisterClass( ATOM atom, HINSTANCE hInstance, BOOL local,
classPtr->cbClsExtra = classExtra;
classPtr->hInstance = hInstance;
classPtr->atomName = atom;
classPtr->dce = (style & CS_CLASSDC) ? DCE_AllocDCE( 0, DCE_CLASS_DC ) : NULL;
/* Other non-null values must be set by caller */
@ -509,7 +505,6 @@ void CLASS_AddWindow( CLASS *class, WND *win, WINDOWPROCTYPE type )
}
win->class = class;
win->clsStyle = class->style;
win->dce = class->dce;
}

View file

@ -1,670 +0,0 @@
/*
* USER DCE functions
*
* Copyright 1993 Alexandre Julliard
* 1996,1997 Alex Korobka
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Note: Visible regions of CS_OWNDC/CS_CLASSDC window DCs
* have to be updated dynamically.
*
* Internal DCX flags:
*
* DCX_DCEEMPTY - dce is uninitialized
* DCX_DCEBUSY - dce is in use
* DCX_DCEDIRTY - ReleaseDC() should wipe instead of caching
* DCX_WINDOWPAINT - BeginPaint() is in effect
*/
#include <assert.h>
#include "dce.h"
#include "win.h"
#include "user_private.h"
#include "windef.h"
#include "wingdi.h"
#include "wownt32.h"
#include "wine/winbase16.h"
#include "wine/winuser16.h"
#include "wine/debug.h"
#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(dc);
typedef struct tagDCE
{
struct list entry;
HDC hDC;
HWND hwndCurrent;
HRGN hClipRgn;
DCE_TYPE type;
DWORD DCXflags;
} DCE;
static struct list dce_list = LIST_INIT(dce_list);
static void DCE_DeleteClipRgn( DCE* );
static INT DCE_ReleaseDC( DCE* );
/***********************************************************************
* DCE_DumpCache
*/
static void DCE_DumpCache(void)
{
DCE *dce;
USER_Lock();
LIST_FOR_EACH_ENTRY( dce, &dce_list, DCE, entry )
{
TRACE("\t[0x%08x] hWnd %p, dcx %08x, %s %s\n",
(unsigned)dce, dce->hwndCurrent, (unsigned)dce->DCXflags,
(dce->DCXflags & DCX_CACHE) ? "Cache" : "Owned",
(dce->DCXflags & DCX_DCEBUSY) ? "InUse" : "" );
}
USER_Unlock();
}
/***********************************************************************
* DCE_AllocDCE
*
* Allocate a new DCE.
*/
DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
{
static const WCHAR szDisplayW[] = { 'D','I','S','P','L','A','Y','\0' };
DCE * dce;
TRACE("(%p,%d)\n", hWnd, type);
if (!(dce = HeapAlloc( GetProcessHeap(), 0, sizeof(DCE) ))) return NULL;
if (!(dce->hDC = CreateDCW( szDisplayW, NULL, NULL, NULL )))
{
HeapFree( GetProcessHeap(), 0, dce );
return 0;
}
SaveDC( dce->hDC );
/* store DCE handle in DC hook data field */
SetDCHook( dce->hDC, DCHook16, (DWORD)dce );
dce->hwndCurrent = hWnd;
dce->hClipRgn = 0;
dce->type = type;
if( type != DCE_CACHE_DC ) /* owned or class DC */
{
dce->DCXflags = DCX_DCEBUSY;
if( hWnd )
{
LONG style = GetWindowLongW( hWnd, GWL_STYLE );
if (style & WS_CLIPCHILDREN) dce->DCXflags |= DCX_CLIPCHILDREN;
if (style & WS_CLIPSIBLINGS) dce->DCXflags |= DCX_CLIPSIBLINGS;
}
SetHookFlags16( HDC_16(dce->hDC), DCHF_INVALIDATEVISRGN );
}
else dce->DCXflags = DCX_CACHE | DCX_DCEEMPTY;
USER_Lock();
list_add_head( &dce_list, &dce->entry );
USER_Unlock();
return dce;
}
/***********************************************************************
* DCE_FreeDCE
*/
void DCE_FreeDCE( DCE *dce )
{
if (!dce) return;
USER_Lock();
list_remove( &dce->entry );
USER_Unlock();
SetDCHook(dce->hDC, NULL, 0L);
DeleteDC( dce->hDC );
if (dce->hClipRgn) DeleteObject(dce->hClipRgn);
HeapFree( GetProcessHeap(), 0, dce );
}
/***********************************************************************
* DCE_FreeWindowDCE
*
* Remove owned DCE and reset unreleased cache DCEs.
*/
void DCE_FreeWindowDCE( HWND hwnd )
{
struct list *ptr, *next;
WND *pWnd = WIN_GetPtr( hwnd );
LIST_FOR_EACH_SAFE( ptr, next, &dce_list )
{
DCE *pDCE = LIST_ENTRY( ptr, DCE, entry );
if (pDCE->hwndCurrent != hwnd) continue;
switch( pDCE->type )
{
case DCE_WINDOW_DC:
DCE_FreeDCE( pDCE );
pWnd->dce = NULL;
break;
case DCE_CLASS_DC:
if( pDCE->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN) )
{
if (USER_Driver.pReleaseDC)
USER_Driver.pReleaseDC( pDCE->hwndCurrent, pDCE->hDC );
DCE_DeleteClipRgn( pDCE );
pDCE->hwndCurrent = 0;
}
break;
case DCE_CACHE_DC:
if( pDCE->DCXflags & DCX_DCEBUSY ) /* shared cache DCE */
{
WARN("[%p] GetDC() without ReleaseDC()!\n",hwnd);
DCE_ReleaseDC( pDCE );
}
if (pDCE->hwndCurrent && USER_Driver.pReleaseDC)
USER_Driver.pReleaseDC( pDCE->hwndCurrent, pDCE->hDC );
pDCE->DCXflags &= DCX_CACHE;
pDCE->DCXflags |= DCX_DCEEMPTY;
pDCE->hwndCurrent = 0;
break;
}
}
WIN_ReleasePtr( pWnd );
}
/***********************************************************************
* DCE_DeleteClipRgn
*/
static void DCE_DeleteClipRgn( DCE* dce )
{
dce->DCXflags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN | DCX_WINDOWPAINT);
if (dce->hClipRgn) DeleteObject( dce->hClipRgn );
dce->hClipRgn = 0;
/* make it dirty so that the vis rgn gets recomputed next time */
dce->DCXflags |= DCX_DCEDIRTY;
SetHookFlags16( HDC_16(dce->hDC), DCHF_INVALIDATEVISRGN );
}
/***********************************************************************
* DCE_ReleaseDC
*/
static INT DCE_ReleaseDC( DCE* dce )
{
if ((dce->DCXflags & (DCX_DCEEMPTY | DCX_DCEBUSY)) != DCX_DCEBUSY) return 0;
/* restore previous visible region */
if ((dce->DCXflags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
(dce->DCXflags & (DCX_CACHE | DCX_WINDOWPAINT)) )
DCE_DeleteClipRgn( dce );
if (dce->DCXflags & DCX_CACHE)
{
/* make the DC clean so that RestoreDC doesn't try to update the vis rgn */
SetHookFlags16( HDC_16(dce->hDC), DCHF_VALIDATEVISRGN );
RestoreDC( dce->hDC, 1 ); /* initial save level is always 1 */
SaveDC( dce->hDC ); /* save the state again for next time */
dce->DCXflags &= ~DCX_DCEBUSY;
if (dce->DCXflags & DCX_DCEDIRTY)
{
/* don't keep around invalidated entries
* because RestoreDC() disables hVisRgn updates
* by removing dirty bit. */
if (dce->hwndCurrent && USER_Driver.pReleaseDC)
USER_Driver.pReleaseDC( dce->hwndCurrent, dce->hDC );
dce->hwndCurrent = 0;
dce->DCXflags &= DCX_CACHE;
dce->DCXflags |= DCX_DCEEMPTY;
}
}
return 1;
}
/***********************************************************************
* DCE_InvalidateDCE
*
* It is called from SetWindowPos() and EVENT_MapNotify - we have to
* mark as dirty all busy DCEs for windows that have pWnd->parent as
* an ancestor and whose client rect intersects with specified update
* rectangle. In addition, pWnd->parent DCEs may need to be updated if
* DCX_CLIPCHILDREN flag is set. */
BOOL DCE_InvalidateDCE(HWND hwnd, const RECT* pRectUpdate)
{
HWND hwndScope = GetAncestor( hwnd, GA_PARENT );
BOOL bRet = FALSE;
if( hwndScope )
{
DCE *dce;
TRACE("scope hwnd = %p, (%ld,%ld - %ld,%ld)\n",
hwndScope, pRectUpdate->left,pRectUpdate->top,
pRectUpdate->right,pRectUpdate->bottom);
if(TRACE_ON(dc))
DCE_DumpCache();
/* walk all DCEs and fixup non-empty entries */
LIST_FOR_EACH_ENTRY( dce, &dce_list, DCE, entry )
{
if (dce->DCXflags & DCX_DCEEMPTY) continue;
if ((dce->hwndCurrent == hwndScope) && !(dce->DCXflags & DCX_CLIPCHILDREN))
continue; /* child window positions don't bother us */
/* check if DCE window is within the z-order scope */
if (hwndScope == dce->hwndCurrent || IsChild( hwndScope, dce->hwndCurrent ))
{
if (hwnd != dce->hwndCurrent)
{
/* check if the window rectangle intersects this DCE window */
RECT rect;
GetWindowRect( dce->hwndCurrent, &rect );
MapWindowPoints( 0, hwndScope, (POINT *)&rect, 2 );
if (!IntersectRect( &rect, &rect, pRectUpdate )) continue;
}
if( !(dce->DCXflags & DCX_DCEBUSY) )
{
/* Don't bother with visible regions of unused DCEs */
TRACE("\tpurged %p dce [%p]\n", dce, dce->hwndCurrent);
if (dce->hwndCurrent && USER_Driver.pReleaseDC)
USER_Driver.pReleaseDC( dce->hwndCurrent, dce->hDC );
dce->hwndCurrent = 0;
dce->DCXflags &= DCX_CACHE;
dce->DCXflags |= DCX_DCEEMPTY;
}
else
{
/* Set dirty bits in the hDC and DCE structs */
TRACE("\tfixed up %p dce [%p]\n", dce, dce->hwndCurrent);
dce->DCXflags |= DCX_DCEDIRTY;
SetHookFlags16( HDC_16(dce->hDC), DCHF_INVALIDATEVISRGN );
bRet = TRUE;
}
}
} /* dce list */
}
return bRet;
}
/***********************************************************************
* GetDCEx (USER32.@)
*
* Unimplemented flags: DCX_LOCKWINDOWUPDATE
*
* FIXME: Full support for hrgnClip == 1 (alias for entire window).
*/
HDC WINAPI GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags )
{
HDC hdc = 0;
DCE * dce;
WND * wndPtr;
DWORD dcxFlags = 0;
BOOL bUpdateVisRgn = TRUE;
BOOL bUpdateClipOrigin = FALSE;
HWND parent;
LONG window_style;
TRACE("hwnd %p, hrgnClip %p, flags %08lx\n", hwnd, hrgnClip, flags);
if (flags & (DCX_LOCKWINDOWUPDATE)) {
FIXME("not yet supported - see source\n");
/* See the comment in LockWindowUpdate for more explanation. This flag is not implemented
* by that patch, but we need LockWindowUpdate implemented correctly before this can be done.
*/
}
if (!hwnd) hwnd = GetDesktopWindow();
else hwnd = WIN_GetFullHandle( hwnd );
if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
{
wndPtr = NULL;
USER_Lock();
}
window_style = GetWindowLongW( hwnd, GWL_STYLE );
/* fixup flags */
if (flags & (DCX_WINDOW | DCX_PARENTCLIP)) flags |= DCX_CACHE;
if (flags & DCX_USESTYLE)
{
flags &= ~( DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS | DCX_PARENTCLIP);
if( window_style & WS_CLIPSIBLINGS )
flags |= DCX_CLIPSIBLINGS;
if ( !(flags & DCX_WINDOW) )
{
if (GetClassLongW( hwnd, GCL_STYLE ) & CS_PARENTDC) flags |= DCX_PARENTCLIP;
if (window_style & WS_CLIPCHILDREN && !(window_style & WS_MINIMIZE))
flags |= DCX_CLIPCHILDREN;
if (!wndPtr || !wndPtr->dce) flags |= DCX_CACHE;
}
}
if (flags & DCX_WINDOW) flags &= ~DCX_CLIPCHILDREN;
parent = GetAncestor( hwnd, GA_PARENT );
if (!parent || (parent == GetDesktopWindow()))
flags = (flags & ~DCX_PARENTCLIP) | DCX_CLIPSIBLINGS;
/* it seems parent clip is ignored when clipping siblings or children */
if (flags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN)) flags &= ~DCX_PARENTCLIP;
if( flags & DCX_PARENTCLIP )
{
LONG parent_style = GetWindowLongW( parent, GWL_STYLE );
if( (window_style & WS_VISIBLE) && (parent_style & WS_VISIBLE) )
{
flags &= ~DCX_CLIPCHILDREN;
if (parent_style & WS_CLIPSIBLINGS) flags |= DCX_CLIPSIBLINGS;
}
}
/* find a suitable DCE */
dcxFlags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
DCX_CACHE | DCX_WINDOW);
if (flags & DCX_CACHE)
{
DCE *dceEmpty = NULL, *dceUnused = NULL;
/* Strategy: First, we attempt to find a non-empty but unused DCE with
* compatible flags. Next, we look for an empty entry. If the cache is
* full we have to purge one of the unused entries.
*/
LIST_FOR_EACH_ENTRY( dce, &dce_list, DCE, entry )
{
if ((dce->DCXflags & (DCX_CACHE | DCX_DCEBUSY)) == DCX_CACHE )
{
dceUnused = dce;
if (dce->DCXflags & DCX_DCEEMPTY)
dceEmpty = dce;
else
if ((dce->hwndCurrent == hwnd) &&
((dce->DCXflags & (DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
DCX_CACHE | DCX_WINDOW | DCX_PARENTCLIP)) == dcxFlags))
{
TRACE("\tfound valid %p dce [%p], flags %08lx\n",
dce, hwnd, dcxFlags );
bUpdateVisRgn = FALSE;
bUpdateClipOrigin = TRUE;
break;
}
}
}
if (&dce->entry == &dce_list) /* nothing found */
dce = dceEmpty ? dceEmpty : dceUnused;
/* if there's no dce empty or unused, allocate a new one */
if (!dce)
{
dce = DCE_AllocDCE( 0, DCE_CACHE_DC );
}
}
else
{
dce = wndPtr->dce;
if (dce && dce->hwndCurrent == hwnd)
{
TRACE("\tskipping hVisRgn update\n");
bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */
}
}
if (!dce)
{
hdc = 0;
goto END;
}
if (!(flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN))) hrgnClip = 0;
if (((flags ^ dce->DCXflags) & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) &&
(dce->hClipRgn != hrgnClip))
{
/* if the extra clip region has changed, get rid of the old one */
DCE_DeleteClipRgn( dce );
}
dce->hwndCurrent = hwnd;
dce->hClipRgn = hrgnClip;
dce->DCXflags = flags & (DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN |
DCX_CACHE | DCX_WINDOW | DCX_WINDOWPAINT |
DCX_INTERSECTRGN | DCX_EXCLUDERGN);
dce->DCXflags |= DCX_DCEBUSY;
dce->DCXflags &= ~DCX_DCEDIRTY;
hdc = dce->hDC;
if (bUpdateVisRgn) SetHookFlags16( HDC_16(hdc), DCHF_INVALIDATEVISRGN ); /* force update */
if (!USER_Driver.pGetDC || !USER_Driver.pGetDC( hwnd, hdc, hrgnClip, flags ))
hdc = 0;
TRACE("(%p,%p,0x%lx): returning %p\n", hwnd, hrgnClip, flags, hdc);
END:
if (wndPtr) WIN_ReleasePtr(wndPtr);
else USER_Unlock();
return hdc;
}
/***********************************************************************
* GetDC (USER32.@)
*
* Get a device context.
*
* RETURNS
* Success: Handle to the device context
* Failure: NULL.
*/
HDC WINAPI GetDC( HWND hwnd )
{
if (!hwnd)
return GetDCEx( 0, 0, DCX_CACHE | DCX_WINDOW );
return GetDCEx( hwnd, 0, DCX_USESTYLE );
}
/***********************************************************************
* GetWindowDC (USER32.@)
*/
HDC WINAPI GetWindowDC( HWND hwnd )
{
return GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW );
}
/***********************************************************************
* ReleaseDC (USER32.@)
*
* Release a device context.
*
* RETURNS
* Success: Non-zero. Resources used by hdc are released.
* Failure: 0.
*/
INT WINAPI ReleaseDC( HWND hwnd, HDC hdc )
{
DCE * dce;
INT nRet = 0;
TRACE("%p %p\n", hwnd, hdc );
USER_Lock();
LIST_FOR_EACH_ENTRY( dce, &dce_list, DCE, entry )
{
if (dce->hDC == hdc)
{
if ( dce->DCXflags & DCX_DCEBUSY )
nRet = DCE_ReleaseDC( dce );
break;
}
}
USER_Unlock();
return nRet;
}
/***********************************************************************
* DCHook (USER.362)
*
* See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags)..
*/
BOOL16 WINAPI DCHook16( HDC16 hDC, WORD code, DWORD data, LPARAM lParam )
{
BOOL retv = TRUE;
DCE *dce = (DCE *)data;
TRACE("hDC = %04x, %i\n", hDC, code);
if (!dce) return 0;
assert( HDC_16(dce->hDC) == hDC );
/* Grab the windows lock before doing anything else */
USER_Lock();
switch( code )
{
case DCHC_INVALIDVISRGN:
/* GDI code calls this when it detects that the
* DC is dirty (usually after SetHookFlags()). This
* means that we have to recompute the visible region.
*/
if( dce->DCXflags & DCX_DCEBUSY )
{
/* Dirty bit has been cleared by caller, set it again so that
* pGetDC recomputes the visible region. */
SetHookFlags16( hDC, DCHF_INVALIDATEVISRGN );
if (USER_Driver.pGetDC)
USER_Driver.pGetDC( dce->hwndCurrent, dce->hDC, dce->hClipRgn, dce->DCXflags );
}
else /* non-fatal but shouldn't happen */
WARN("DC is not in use!\n");
break;
case DCHC_DELETEDC:
/*
* Windows will not let you delete a DC that is busy
* (between GetDC and ReleaseDC)
*/
if ( dce->DCXflags & DCX_DCEBUSY )
{
WARN("Application trying to delete a busy DC\n");
retv = FALSE;
}
else DCE_FreeDCE( dce );
break;
default:
FIXME("unknown code\n");
}
USER_Unlock(); /* Release the wnd lock */
return retv;
}
/**********************************************************************
* WindowFromDC (USER32.@)
*/
HWND WINAPI WindowFromDC( HDC hDC )
{
DCE *dce;
HWND hwnd = 0;
USER_Lock();
LIST_FOR_EACH_ENTRY( dce, &dce_list, DCE, entry )
{
if (dce->hDC == hDC)
{
hwnd = dce->hwndCurrent;
break;
}
}
USER_Unlock();
return hwnd;
}
/***********************************************************************
* LockWindowUpdate (USER32.@)
*/
BOOL WINAPI LockWindowUpdate( HWND hwnd )
{
static HWND lockedWnd;
/* This function is fully implemented by the following patch:
*
* http://www.winehq.org/hypermail/wine-patches/2004/01/0142.html
*
* but in order to work properly, it needs the ability to invalidate
* DCEs in other processes when the lock window is changed, which
* isn't possible yet.
* -mike
*/
FIXME("(%p), partial stub!\n",hwnd);
USER_Lock();
if (lockedWnd)
{
if (!hwnd)
{
/* Unlock lockedWnd */
/* FIXME: Do something */
}
else
{
/* Attempted to lock a second window */
/* Return FALSE and do nothing */
USER_Unlock();
return FALSE;
}
}
lockedWnd = hwnd;
USER_Unlock();
return TRUE;
}

View file

@ -29,7 +29,6 @@
#include "wownt32.h"
#include "win.h"
#include "user_private.h"
#include "dce.h"
#include "controls.h"
#include "cursoricon.h"
#include "winpos.h"

View file

@ -34,7 +34,6 @@
#include "wine/unicode.h"
#include "win.h"
#include "user_private.h"
#include "dce.h"
#include "controls.h"
#include "cursoricon.h"
#include "message.h"
@ -578,7 +577,6 @@ LRESULT WIN_DestroyWindow( HWND hwnd )
if (menu) DestroyMenu( menu );
if (sys_menu) DestroyMenu( sys_menu );
DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
if (USER_Driver.pDestroyWindow) USER_Driver.pDestroyWindow( hwnd );
free_window_handle( hwnd );
@ -1066,10 +1064,6 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
}
SERVER_END_REQ;
/* Get class or window DC if needed */
if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
/* Set the window menu */
if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||