Moved DCE support to the X11 driver.
This commit is contained in:
parent
dc84b8a4c7
commit
2fb7c8754a
|
@ -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 \
|
||||
|
|
|
@ -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.@)
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ C_SRCS = \
|
|||
clipboard.c \
|
||||
clipping.c \
|
||||
codepage.c \
|
||||
dce.c \
|
||||
desktop.c \
|
||||
dga2.c \
|
||||
dib.c \
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
670
windows/dce.c
670
windows/dce.c
|
@ -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;
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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) ||
|
||||
|
|
Loading…
Reference in New Issue