From 1642fbcbc2b4133cf0ce29c3539082cc1027180b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 25 Feb 2008 15:59:19 +0100 Subject: [PATCH] user32: Moved the DCE support from winex11 back to user32. Window and class DCEs are now allocated lazily. --- dlls/user32/class.c | 22 ++ dlls/user32/controls.h | 2 + dlls/user32/driver.c | 35 +- dlls/user32/painting.c | 590 +++++++++++++++++++++++++++++++++- dlls/user32/tests/dce.c | 1 - dlls/user32/user32.spec | 1 + dlls/user32/user_private.h | 9 +- dlls/user32/win.c | 8 +- dlls/user32/winpos.c | 12 +- dlls/winex11.drv/Makefile.in | 1 - dlls/winex11.drv/dce.c | 655 -------------------------------------- dlls/winex11.drv/opengl.c | 2 - dlls/winex11.drv/window.c | 95 +++--- dlls/winex11.drv/winex11.drv.spec | 5 +- dlls/winex11.drv/winpos.c | 21 +- dlls/winex11.drv/x11drv.h | 14 - include/win.h | 1 + 17 files changed, 705 insertions(+), 769 deletions(-) delete mode 100644 dlls/winex11.drv/dce.c diff --git a/dlls/user32/class.c b/dlls/user32/class.c index 94bc639a23a..ff0e1f804b6 100644 --- a/dlls/user32/class.c +++ b/dlls/user32/class.c @@ -52,6 +52,7 @@ typedef struct tagCLASS INT cbClsExtra; /* Class extra bytes */ INT cbWndExtra; /* Window extra bytes */ LPWSTR menuName; /* Default menu name (Unicode followed by ASCII) */ + struct dce *dce; /* Opaque pointer to class DCE */ HINSTANCE hInstance; /* Module that created the task */ HICON hIcon; /* Default icon */ HICON hIconSm; /* Default small icon */ @@ -243,6 +244,7 @@ static void CLASS_FreeClass( CLASS *classPtr ) USER_Lock(); + if (classPtr->dce) free_dce( classPtr->dce, 0 ); list_remove( &classPtr->entry ); if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1)) DeleteObject( classPtr->hbrBackground ); @@ -442,6 +444,26 @@ WNDPROC get_class_winproc( CLASS *class ) /*********************************************************************** + * get_class_dce + */ +struct dce *get_class_dce( CLASS *class ) +{ + return class->dce; +} + + +/*********************************************************************** + * set_class_dce + */ +struct dce *set_class_dce( CLASS *class, struct dce *dce ) +{ + if (class->dce) return class->dce; /* already set, don't change it */ + class->dce = dce; + return dce; +} + + +/*********************************************************************** * RegisterClassA (USER32.@) * * Register a window class. diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h index ef564324580..4bfe7fd42f4 100644 --- a/dlls/user32/controls.h +++ b/dlls/user32/controls.h @@ -64,6 +64,8 @@ struct tagWND; extern ATOM get_int_atom_value( LPCWSTR name ) DECLSPEC_HIDDEN; extern void CLASS_RegisterBuiltinClasses(void) DECLSPEC_HIDDEN; extern WNDPROC get_class_winproc( struct tagCLASS *class ) DECLSPEC_HIDDEN; +extern struct dce *get_class_dce( struct tagCLASS *class ) DECLSPEC_HIDDEN; +extern struct dce *set_class_dce( struct tagCLASS *class, struct dce *dce ) DECLSPEC_HIDDEN; extern void CLASS_FreeModuleClasses( HMODULE16 hModule ) DECLSPEC_HIDDEN; /* defwnd proc */ diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c index 9335db7f1f3..d5f1fa08222 100644 --- a/dlls/user32/driver.c +++ b/dlls/user32/driver.c @@ -108,7 +108,7 @@ static const USER_DRIVER *load_driver(void) GET_USER_FUNC(CreateDesktopWindow); GET_USER_FUNC(CreateWindow); GET_USER_FUNC(DestroyWindow); - GET_USER_FUNC(GetDCEx); + GET_USER_FUNC(GetDC); GET_USER_FUNC(MsgWaitForMultipleObjectsEx); GET_USER_FUNC(ReleaseDC); GET_USER_FUNC(ScrollDC); @@ -121,7 +121,6 @@ static const USER_DRIVER *load_driver(void) GET_USER_FUNC(SetWindowText); GET_USER_FUNC(ShowWindow); GET_USER_FUNC(SysCommandSizeMove); - GET_USER_FUNC(WindowFromDC); GET_USER_FUNC(WindowMessage); #undef GET_USER_FUNC } @@ -344,9 +343,9 @@ static void nulldrv_DestroyWindow( HWND hwnd ) { } -static HDC nulldrv_GetDCEx( HWND hwnd, HRGN hrgn, DWORD flags ) +static void nulldrv_GetDC( HDC hdc, HWND hwnd, HWND top_win, const RECT *win_rect, + const RECT *top_rect, DWORD flags ) { - return 0; } static DWORD nulldrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, @@ -356,9 +355,8 @@ static DWORD nulldrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *han timeout, flags & MWMO_ALERTABLE ); } -static INT nulldrv_ReleaseDC( HWND hwnd, HDC hdc, BOOL end_paint ) +static void nulldrv_ReleaseDC( HWND hwnd, HDC hdc ) { - return 0; } static BOOL nulldrv_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, @@ -407,11 +405,6 @@ static void nulldrv_SysCommandSizeMove( HWND hwnd, WPARAM wparam ) { } -static HWND nulldrv_WindowFromDC( HDC hdc ) -{ - return 0; -} - static LRESULT nulldrv_WindowMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { return 0; @@ -461,7 +454,7 @@ static const USER_DRIVER null_driver = nulldrv_CreateDesktopWindow, nulldrv_CreateWindow, nulldrv_DestroyWindow, - nulldrv_GetDCEx, + nulldrv_GetDC, nulldrv_MsgWaitForMultipleObjectsEx, nulldrv_ReleaseDC, nulldrv_ScrollDC, @@ -474,7 +467,6 @@ static const USER_DRIVER null_driver = nulldrv_SetWindowText, nulldrv_ShowWindow, nulldrv_SysCommandSizeMove, - nulldrv_WindowFromDC, nulldrv_WindowMessage }; @@ -668,9 +660,10 @@ static void loaderdrv_DestroyWindow( HWND hwnd ) load_driver()->pDestroyWindow( hwnd ); } -static HDC loaderdrv_GetDCEx( HWND hwnd, HRGN hrgn, DWORD flags ) +static void loaderdrv_GetDC( HDC hdc, HWND hwnd, HWND top_win, const RECT *win_rect, + const RECT *top_rect, DWORD flags ) { - return load_driver()->pGetDCEx( hwnd, hrgn, flags ); + load_driver()->pGetDC( hdc, hwnd, top_win, win_rect, top_rect, flags ); } static DWORD loaderdrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, @@ -679,9 +672,9 @@ static DWORD loaderdrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *h return load_driver()->pMsgWaitForMultipleObjectsEx( count, handles, timeout, mask, flags ); } -static INT loaderdrv_ReleaseDC( HWND hwnd, HDC hdc, BOOL end_paint ) +static void loaderdrv_ReleaseDC( HWND hwnd, HDC hdc ) { - return load_driver()->pReleaseDC( hwnd, hdc, end_paint ); + load_driver()->pReleaseDC( hwnd, hdc ); } static BOOL loaderdrv_ScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, @@ -738,11 +731,6 @@ static void loaderdrv_SysCommandSizeMove( HWND hwnd, WPARAM wparam ) load_driver()->pSysCommandSizeMove( hwnd, wparam ); } -static HWND loaderdrv_WindowFromDC( HDC hdc ) -{ - return load_driver()->pWindowFromDC( hdc ); -} - static LRESULT loaderdrv_WindowMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { return load_driver()->pWindowMessage( hwnd, msg, wparam, lparam ); @@ -792,7 +780,7 @@ static const USER_DRIVER lazy_load_driver = loaderdrv_CreateDesktopWindow, loaderdrv_CreateWindow, loaderdrv_DestroyWindow, - loaderdrv_GetDCEx, + loaderdrv_GetDC, loaderdrv_MsgWaitForMultipleObjectsEx, loaderdrv_ReleaseDC, loaderdrv_ScrollDC, @@ -805,6 +793,5 @@ static const USER_DRIVER lazy_load_driver = loaderdrv_SetWindowText, loaderdrv_ShowWindow, loaderdrv_SysCommandSizeMove, - loaderdrv_WindowFromDC, loaderdrv_WindowMessage }; diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index 93fe97cf869..576ccdbe614 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -1,8 +1,8 @@ /* * Window painting functions * - * Copyright 1993, 1994, 1995, 2001, 2004 Alexandre Julliard - * Copyright 1999 Alex Korobka + * Copyright 1993, 1994, 1995, 2001, 2004, 2005, 2008 Alexandre Julliard + * Copyright 1996, 1997, 1999 Alex Korobka * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +22,7 @@ #include "config.h" #include "wine/port.h" +#include #include #include @@ -34,11 +35,31 @@ #include "wine/server.h" #include "win.h" #include "user_private.h" +#include "controls.h" +#include "wine/list.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(win); +struct dce +{ + struct list entry; /* entry in global DCE list */ + HDC hdc; + HWND hwnd; + HRGN clip_rgn; + DWORD flags; + LONG count; /* usage count; 0 or 1 for cache DCEs, always 1 for window DCEs, + always >= 1 for class DCEs */ +}; + +static struct list dce_list = LIST_INIT(dce_list); + +static BOOL CALLBACK dc_hook( HDC hDC, WORD code, DWORD_PTR data, LPARAM lParam ); + +static const WCHAR displayW[] = { 'D','I','S','P','L','A','Y',0 }; + + /*********************************************************************** * dump_rdw_flags */ @@ -79,6 +100,420 @@ static void dump_rdw_flags(UINT flags) /*********************************************************************** + * update_visible_region + * + * Set the visible region and X11 drawable for the DC associated to + * a given window. + */ +static void update_visible_region( struct dce *dce ) +{ + NTSTATUS status; + HRGN vis_rgn = 0; + HWND top_win = 0; + DWORD flags = dce->flags; + size_t size = 256; + RECT win_rect, top_rect; + + /* don't clip siblings if using parent clip region */ + if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS; + + /* fetch the visible region from the server */ + do + { + RGNDATA *data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ); + if (!data) return; + + SERVER_START_REQ( get_visible_region ) + { + req->window = dce->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; + vis_rgn = ExtCreateRegion( NULL, size, data ); + + top_win = reply->top_win; + win_rect.left = reply->win_rect.left; + win_rect.top = reply->win_rect.top; + win_rect.right = reply->win_rect.right; + win_rect.bottom = reply->win_rect.bottom; + top_rect.left = reply->top_rect.left; + top_rect.top = reply->top_rect.top; + top_rect.right = reply->top_rect.right; + top_rect.bottom = reply->top_rect.bottom; + } + else size = reply->total_size; + } + SERVER_END_REQ; + HeapFree( GetProcessHeap(), 0, data ); + } while (status == STATUS_BUFFER_OVERFLOW); + + if (status || !vis_rgn) return; + + USER_Driver->pGetDC( dce->hdc, dce->hwnd, top_win, &win_rect, &top_rect, flags ); + + if (dce->clip_rgn) CombineRgn( vis_rgn, vis_rgn, dce->clip_rgn, + (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); + + /* map region to DC coordinates */ + OffsetRgn( vis_rgn, -win_rect.left, -win_rect.top ); + SelectVisRgn( dce->hdc, vis_rgn ); + DeleteObject( vis_rgn ); +} + + +/*********************************************************************** + * release_dce + */ +static void release_dce( struct dce *dce ) +{ + if (!dce->hwnd) return; /* already released */ + + USER_Driver->pReleaseDC( dce->hwnd, dce->hdc ); + + if (dce->clip_rgn) DeleteObject( dce->clip_rgn ); + dce->clip_rgn = 0; + dce->hwnd = 0; + dce->flags &= DCX_CACHE; +} + + +/*********************************************************************** + * delete_clip_rgn + */ +static void delete_clip_rgn( struct dce *dce ) +{ + if (!dce->clip_rgn) return; /* nothing to do */ + + dce->flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN); + DeleteObject( dce->clip_rgn ); + dce->clip_rgn = 0; + + /* make it dirty so that the vis rgn gets recomputed next time */ + SetHookFlags( dce->hdc, DCHF_INVALIDATEVISRGN ); +} + + +/*********************************************************************** + * alloc_dce + * + * Allocate a new DCE. + */ +static struct dce *alloc_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 ); + + dce->hwnd = 0; + dce->clip_rgn = 0; + dce->flags = 0; + dce->count = 1; + + /* store DCE handle in DC hook data field */ + SetDCHook( dce->hdc, dc_hook, (DWORD_PTR)dce ); + SetHookFlags( dce->hdc, DCHF_INVALIDATEVISRGN ); + return dce; +} + + +/*********************************************************************** + * get_window_dce + */ +static struct dce *get_window_dce( HWND hwnd ) +{ + struct dce *dce; + WND *win = WIN_GetPtr( hwnd ); + + if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP) return NULL; + + dce = win->dce; + if (!dce && (dce = get_class_dce( win->class ))) + { + win->dce = dce; + dce->count++; + } + WIN_ReleasePtr( win ); + + if (!dce) /* try to allocate one */ + { + struct dce *dce_to_free = NULL; + LONG class_style = GetClassLongW( hwnd, GCL_STYLE ); + + if (class_style & CS_CLASSDC) + { + if (!(dce = alloc_dce())) return NULL; + + win = WIN_GetPtr( hwnd ); + if (win && win != WND_OTHER_PROCESS && win != WND_DESKTOP) + { + if (win->dce) /* another thread beat us to it */ + { + dce_to_free = dce; + dce = win->dce; + } + else if ((win->dce = set_class_dce( win->class, dce )) != dce) + { + dce_to_free = dce; + dce = win->dce; + dce->count++; + } + else + { + dce->count++; + list_add_tail( &dce_list, &dce->entry ); + } + WIN_ReleasePtr( win ); + } + else dce_to_free = dce; + } + else if (class_style & CS_OWNDC) + { + if (!(dce = alloc_dce())) return NULL; + + win = WIN_GetPtr( hwnd ); + if (win && win != WND_OTHER_PROCESS && win != WND_DESKTOP) + { + if (win->dwStyle & WS_CLIPCHILDREN) dce->flags |= DCX_CLIPCHILDREN; + if (win->dwStyle & WS_CLIPSIBLINGS) dce->flags |= DCX_CLIPSIBLINGS; + if (win->dce) /* another thread beat us to it */ + { + dce_to_free = dce; + dce = win->dce; + } + else + { + win->dce = dce; + dce->hwnd = hwnd; + list_add_tail( &dce_list, &dce->entry ); + } + WIN_ReleasePtr( win ); + } + else dce_to_free = dce; + } + + if (dce_to_free) + { + SetDCHook( dce->hdc, NULL, 0 ); + DeleteDC( dce->hdc ); + HeapFree( GetProcessHeap(), 0, dce ); + } + } + return dce; +} + + +/*********************************************************************** + * free_dce + * + * Free a class or window DCE. + */ +void free_dce( struct dce *dce, HWND hwnd ) +{ + USER_Lock(); + + if (dce) + { + if (!--dce->count) + { + /* turn it into a cache entry */ + release_dce( dce ); + dce->flags |= DCX_CACHE; + } + else if (dce->hwnd == hwnd) + { + release_dce( dce ); + } + } + + /* now check for cache DCEs */ + + if (hwnd) + { + LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry ) + { + if (dce->hwnd != hwnd) continue; + if (!(dce->flags & DCX_CACHE)) continue; + + if (dce->count) WARN( "GetDC() without ReleaseDC() for window %p\n", hwnd ); + dce->count = 0; + release_dce( dce ); + } + } + + USER_Unlock(); +} + + +/*********************************************************************** + * make_dc_dirty + * + * Mark the associated DC as dirty to force a refresh of the visible region + */ +static void make_dc_dirty( struct dce *dce ) +{ + if (!dce->count) + { + /* Don't bother with visible regions of unused DCEs */ + TRACE("\tpurged %p dce [%p]\n", dce, dce->hwnd); + release_dce( dce ); + } + else + { + /* Set dirty bits in the hDC and DCE structs */ + TRACE("\tfixed up %p dce [%p]\n", dce, dce->hwnd); + SetHookFlags( dce->hdc, DCHF_INVALIDATEVISRGN ); + } +} + + +/*********************************************************************** + * 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 ) +{ + RECT window_rect, extra_rect; + struct dce *dce; + HWND hwndScope = GetAncestor( hwnd, GA_PARENT ); + + if (!hwndScope) return; + + GetWindowRect( hwnd, &window_rect ); + if (rect) + { + extra_rect = *rect; + MapWindowPoints( hwndScope, 0, (POINT *)&extra_rect, 2 ); + } + + TRACE("%p scope hwnd = %p %s (%s)\n", + hwnd, hwndScope, wine_dbgstr_rect(&window_rect), wine_dbgstr_rect(rect) ); + + /* walk all DCEs and fixup non-empty entries */ + + USER_Lock(); + LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry ) + { + TRACE( "%p: hwnd %p dcx %08x %s %s\n", dce, dce->hwnd, dce->flags, + (dce->flags & DCX_CACHE) ? "Cache" : "Owned", dce->count ? "InUse" : "" ); + + if (!dce->hwnd) continue; + if ((dce->hwnd == hwndScope) && !(dce->flags & DCX_CLIPCHILDREN)) + continue; /* child window positions don't bother us */ + + /* if DCE window is a child of hwnd, it has to be invalidated */ + if (dce->hwnd == hwnd || IsChild( hwnd, dce->hwnd )) + { + make_dc_dirty( dce ); + } + else /* otherwise check if the window rectangle intersects this DCE window */ + { + if (hwndScope == GetDesktopWindow() || + hwndScope == dce->hwnd || IsChild( hwndScope, dce->hwnd )) + { + RECT dce_rect, tmp; + GetWindowRect( dce->hwnd, &dce_rect ); + if (IntersectRect( &tmp, &dce_rect, &window_rect ) || + (rect && IntersectRect( &tmp, &dce_rect, &extra_rect ))) + make_dc_dirty( dce ); + } + } + } + USER_Unlock(); +} + +/*********************************************************************** + * release_dc + * + * Implementation of ReleaseDC. + */ +static INT release_dc( HWND hwnd, HDC hdc, BOOL end_paint ) +{ + struct dce *dce; + BOOL ret = FALSE; + + TRACE("%p %p\n", hwnd, hdc ); + + USER_Lock(); + dce = (struct dce *)GetDCHook( hdc, NULL ); + if (dce && dce->count) + { + if (end_paint || (dce->flags & DCX_CACHE)) delete_clip_rgn( dce ); + if (dce->flags & DCX_CACHE) dce->count = 0; + ret = TRUE; + } + USER_Unlock(); + return ret; +} + + +/*********************************************************************** + * dc_hook + * + * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags).. + */ +static BOOL CALLBACK dc_hook( HDC hDC, WORD code, DWORD_PTR data, LPARAM lParam ) +{ + BOOL retv = TRUE; + struct dce *dce = (struct dce *)data; + + TRACE("hDC = %p, %u\n", hDC, code); + + if (!dce) return 0; + assert( 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->count) update_visible_region( dce ); + 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) + */ + USER_Lock(); + if (dce->count) + { + WARN("Application trying to delete a busy DC %p\n", dce->hdc); + retv = FALSE; + } + else + { + list_remove( &dce->entry ); + if (dce->clip_rgn) DeleteObject( dce->clip_rgn ); + HeapFree( GetProcessHeap(), 0, dce ); + } + USER_Unlock(); + break; + } + return retv; +} + + +/*********************************************************************** * get_update_region * * Return update region (in screen coordinates) for a window. @@ -263,7 +698,7 @@ static BOOL send_erase( HWND hwnd, UINT flags, HRGN client_rgn, if (type != NULLREGION) need_erase = !SendMessageW( hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0 ); } - if (!hdc_ret) USER_Driver->pReleaseDC( hwnd, hdc, TRUE ); + if (!hdc_ret) release_dc( hwnd, hdc, TRUE ); } if (hdc_ret) *hdc_ret = hdc; @@ -457,7 +892,7 @@ HDC WINAPI BeginPaint( HWND hwnd, PAINTSTRUCT *lps ) BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps ) { if (!lps) return FALSE; - USER_Driver->pReleaseDC( hwnd, lps->hdc, TRUE ); + release_dc( hwnd, lps->hdc, TRUE ); ShowCaret( hwnd ); return TRUE; } @@ -468,10 +903,142 @@ BOOL WINAPI EndPaint( HWND hwnd, const PAINTSTRUCT *lps ) */ HDC WINAPI GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags ) { + static const DWORD clip_flags = DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW; + struct dce *dce; + BOOL bUpdateVisRgn = TRUE; + HWND parent; + LONG window_style = GetWindowLongW( hwnd, GWL_STYLE ); + if (!hwnd) hwnd = GetDesktopWindow(); else hwnd = WIN_GetFullHandle( hwnd ); - return USER_Driver->pGetDCEx( hwnd, hrgnClip, flags ); + TRACE("hwnd %p, hrgnClip %p, flags %08x\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 (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 */ + + if ((flags & DCX_CACHE) || !(dce = get_window_dce( hwnd ))) + { + 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. + */ + USER_Lock(); + LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry ) + { + if ((dce->flags & DCX_CACHE) && !dce->count) + { + dceUnused = dce; + + if (!dce->hwnd) dceEmpty = dce; + else if ((dce->hwnd == hwnd) && !((dce->flags ^ flags) & clip_flags)) + { + TRACE("\tfound valid %p dce [%p], flags %08x\n", + dce, hwnd, dce->flags ); + bUpdateVisRgn = FALSE; + break; + } + } + } + + if (&dce->entry == &dce_list) /* nothing found */ + dce = dceEmpty ? dceEmpty : dceUnused; + + if (dce) dce->count = 1; + + USER_Unlock(); + + /* if there's no dce empty or unused, allocate a new one */ + if (!dce) + { + if (!(dce = alloc_dce())) return 0; + dce->flags = DCX_CACHE; + USER_Lock(); + list_add_head( &dce_list, &dce->entry ); + USER_Unlock(); + } + } + else + { + flags |= DCX_NORESETATTRS; + if (dce->hwnd == hwnd) + { + TRACE("\tskipping hVisRgn update\n"); + bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */ + } + else + { + /* we should free dce->clip_rgn here, but Windows apparently doesn't */ + dce->flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN); + dce->clip_rgn = 0; + } + } + + if (flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) + { + /* if the extra clip region has changed, get rid of the old one */ + if (dce->clip_rgn != hrgnClip || ((flags ^ dce->flags) & (DCX_INTERSECTRGN | DCX_EXCLUDERGN))) + delete_clip_rgn( dce ); + dce->clip_rgn = hrgnClip; + if (!dce->clip_rgn) dce->clip_rgn = CreateRectRgn( 0, 0, 0, 0 ); + dce->flags |= flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN); + bUpdateVisRgn = TRUE; + } + + dce->hwnd = hwnd; + dce->flags = (dce->flags & ~clip_flags) | (flags & clip_flags); + + if (SetHookFlags( dce->hdc, DCHF_VALIDATEVISRGN )) bUpdateVisRgn = TRUE; /* DC was dirty */ + + if (bUpdateVisRgn) update_visible_region( dce ); + + if (!(flags & DCX_NORESETATTRS)) + { + RestoreDC( dce->hdc, 1 ); /* initial save level is always 1 */ + SaveDC( dce->hdc ); /* save the state again for next time */ + } + + TRACE("(%p,%p,0x%x): returning %p\n", hwnd, hrgnClip, flags, dce->hdc); + return dce->hdc; } @@ -511,16 +1078,23 @@ HDC WINAPI GetWindowDC( HWND hwnd ) */ INT WINAPI ReleaseDC( HWND hwnd, HDC hdc ) { - return USER_Driver->pReleaseDC( hwnd, hdc, FALSE ); + return release_dc( hwnd, hdc, FALSE ); } /********************************************************************** * WindowFromDC (USER32.@) */ -HWND WINAPI WindowFromDC( HDC hDC ) +HWND WINAPI WindowFromDC( HDC hdc ) { - return USER_Driver->pWindowFromDC( hDC ); + struct dce *dce; + HWND hwnd = 0; + + USER_Lock(); + dce = (struct dce *)GetDCHook( hdc, NULL ); + if (dce) hwnd = dce->hwnd; + USER_Unlock(); + return hwnd; } diff --git a/dlls/user32/tests/dce.c b/dlls/user32/tests/dce.c index c9b5fc9b059..fead3850a9c 100644 --- a/dlls/user32/tests/dce.c +++ b/dlls/user32/tests/dce.c @@ -385,7 +385,6 @@ static void test_invisible_create(void) dc1 = GetDC(hwnd_owndc); dc2 = GetDC(hwnd_owndc); -todo_wine ok(dc1 == dc2, "expected owndc dcs to match\n"); ReleaseDC(hwnd_owndc, dc2); diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 7d252cc08e0..6b7e0853b07 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -794,3 +794,4 @@ @ cdecl WINPOS_ShowIconTitle(long long) @ cdecl WIN_GetPtr(long) @ cdecl WIN_SetStyle(long long long) +@ cdecl WIN_invalidate_dce(long ptr) invalidate_dce diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 2f6ac685913..0b5efe28634 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -144,9 +144,9 @@ typedef struct tagUSER_DRIVER { BOOL (*pCreateDesktopWindow)(HWND); BOOL (*pCreateWindow)(HWND); void (*pDestroyWindow)(HWND); - HDC (*pGetDCEx)(HWND,HRGN,DWORD); + void (*pGetDC)(HDC,HWND,HWND,const RECT *,const RECT *,DWORD); DWORD (*pMsgWaitForMultipleObjectsEx)(DWORD,const HANDLE*,DWORD,DWORD,DWORD); - INT (*pReleaseDC)(HWND,HDC,BOOL); + void (*pReleaseDC)(HWND,HDC); BOOL (*pScrollDC)(HDC, INT, INT, const RECT *, const RECT *, HRGN, LPRECT); void (*pSetFocus)(HWND); void (*pSetParent)(HWND,HWND,HWND); @@ -157,7 +157,6 @@ typedef struct tagUSER_DRIVER { void (*pSetWindowText)(HWND,LPCWSTR); BOOL (*pShowWindow)(HWND,INT); void (*pSysCommandSizeMove)(HWND,WPARAM); - HWND (*pWindowFromDC)(HDC); LRESULT (*pWindowMessage)(HWND,UINT,WPARAM,LPARAM); } USER_DRIVER; @@ -231,9 +230,13 @@ extern HMODULE user32_module DECLSPEC_HIDDEN; extern DWORD USER16_AlertableWait DECLSPEC_HIDDEN; extern HBRUSH SYSCOLOR_55AABrush DECLSPEC_HIDDEN; +struct dce; + extern BOOL CLIPBOARD_ReleaseOwner(void) DECLSPEC_HIDDEN; extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL HOOK_IsHooked( INT id ) DECLSPEC_HIDDEN; +extern void free_dce( struct dce *dce, HWND hwnd ) DECLSPEC_HIDDEN; +extern void invalidate_dce( HWND hwnd, const RECT *rect ) DECLSPEC_HIDDEN; extern void erase_now( HWND hwnd, UINT rdw_flags ) DECLSPEC_HIDDEN; extern void *get_hook_proc( void *proc, const WCHAR *module ); extern LRESULT call_current_hook( HHOOK hhook, INT code, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; diff --git a/dlls/user32/win.c b/dlls/user32/win.c index f5fee96b804..bdce3343429 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -522,7 +522,11 @@ ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits ) } SERVER_END_REQ; WIN_ReleasePtr( win ); - if (ok) USER_Driver->pSetWindowStyle( hwnd, old_style ); + if (ok) + { + USER_Driver->pSetWindowStyle( hwnd, old_style ); + if ((old_style ^ new_style) & WS_VISIBLE) invalidate_dce( hwnd, NULL ); + } return old_style; } @@ -631,6 +635,8 @@ LRESULT WIN_DestroyWindow( HWND hwnd ) if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu; sys_menu = wndPtr->hSysMenu; + free_dce( wndPtr->dce, hwnd ); + wndPtr->dce = NULL; WIN_ReleasePtr( wndPtr ); if (menu) DestroyMenu( menu ); diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index daebe7c2e6e..451dd3b5795 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -276,6 +276,7 @@ int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw ) UINT swp_flags = SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE; if (!bRedraw) swp_flags |= SWP_NOREDRAW; SetWindowPos( hwnd, 0, 0, 0, 0, 0, swp_flags ); + invalidate_dce( hwnd, NULL ); } return ret; } @@ -1590,11 +1591,13 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, { WND *win; BOOL ret; - RECT visible_rect; + RECT visible_rect, old_window_rect; + DWORD new_style; if (!(win = WIN_GetPtr( hwnd ))) return FALSE; if (win == WND_DESKTOP || win == WND_OTHER_PROCESS) return FALSE; + old_window_rect = win->rectWindow; SERVER_START_REQ( set_window_pos ) { req->handle = hwnd; @@ -1623,11 +1626,18 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, } } SERVER_END_REQ; + new_style = win->dwStyle; WIN_ReleasePtr( win ); if (ret) + { USER_Driver->pSetWindowPos( hwnd, insert_after, swp_flags, window_rect, client_rect, &visible_rect, valid_rects ); + + if ((((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) && (new_style & WS_VISIBLE)) || + (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW))) + invalidate_dce( hwnd, &old_window_rect ); + } return ret; } diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index 0684fc35c4e..8a3b50922ee 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -14,7 +14,6 @@ C_SRCS = \ clipboard.c \ clipping.c \ codepage.c \ - dce.c \ desktop.c \ dib.c \ dib_convert.c \ diff --git a/dlls/winex11.drv/dce.c b/dlls/winex11.drv/dce.c deleted file mode 100644 index 8ac00079aaf..00000000000 --- a/dlls/winex11.drv/dce.c +++ /dev/null @@ -1,655 +0,0 @@ -/* -* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" - -#include -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "win.h" -#include "windef.h" -#include "wingdi.h" -#include "x11drv.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; - void *class_ptr; /* ptr to identify window class for class DCEs */ - ULONG count; /* usage count; 0 or 1 for cache DCEs, always 1 for window DCEs, - always >= 1 for class DCEs */ -}; - -static struct list dce_list = LIST_INIT(dce_list); - -static BOOL CALLBACK dc_hook( HDC hDC, WORD code, DWORD_PTR 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, { (DWORD_PTR)(__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 %08x %s %s\n", - dce, dce->hwnd, dce->flags, - (dce->flags & DCX_CACHE) ? "Cache" : "Owned", - dce->count ? "InUse" : "" ); - } - - LeaveCriticalSection( &dce_section ); -} - - -/*********************************************************************** - * update_visible_region - * - * Set the visible region and X11 drawable for the DC associated to - * a given window. - */ -static void update_visible_region( struct dce *dce ) -{ - NTSTATUS status; - HRGN vis_rgn = 0; - HWND top = 0; - struct x11drv_escape_set_drawable escape; - struct x11drv_win_data *data; - DWORD flags = dce->flags; - size_t size = 256; - - /* don't clip siblings if using parent clip region */ - if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS; - - /* fetch the visible region from the server */ - do - { - RGNDATA *data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) + size - 1 ); - if (!data) return; - - SERVER_START_REQ( get_visible_region ) - { - req->window = dce->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; - vis_rgn = ExtCreateRegion( NULL, size, data ); - - top = reply->top_win; - escape.dc_rect.left = reply->win_rect.left - reply->top_rect.left; - escape.dc_rect.top = reply->win_rect.top - reply->top_rect.top; - escape.dc_rect.right = reply->win_rect.right - reply->top_rect.left; - escape.dc_rect.bottom = reply->win_rect.bottom - reply->top_rect.top; - escape.drawable_rect.left = reply->top_rect.left; - escape.drawable_rect.top = reply->top_rect.top; - escape.drawable_rect.right = reply->top_rect.right; - escape.drawable_rect.bottom = reply->top_rect.bottom; - } - else size = reply->total_size; - } - SERVER_END_REQ; - HeapFree( GetProcessHeap(), 0, data ); - } while (status == STATUS_BUFFER_OVERFLOW); - - if (status || !vis_rgn) return; - - if (dce->clip_rgn) CombineRgn( vis_rgn, vis_rgn, dce->clip_rgn, - (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); - - escape.fbconfig_id = 0; - escape.gl_drawable = 0; - escape.pixmap = 0; - - if (top == dce->hwnd && ((data = X11DRV_get_win_data( dce->hwnd )) != NULL) && - IsIconic( dce->hwnd ) && data->icon_window) - { - escape.drawable = data->icon_window; - } - else if (top == dce->hwnd && (flags & DCX_WINDOW)) - { - escape.drawable = X11DRV_get_whole_window( top ); - } - else - { - escape.drawable = X11DRV_get_client_window( top ); - escape.fbconfig_id = X11DRV_get_fbconfig_id( dce->hwnd ); - escape.gl_drawable = X11DRV_get_gl_drawable( dce->hwnd ); - escape.pixmap = X11DRV_get_gl_pixmap( dce->hwnd ); - } - - escape.code = X11DRV_SET_DRAWABLE; - escape.mode = IncludeInferiors; - ExtEscape( dce->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); - - /* map region to DC coordinates */ - OffsetRgn( vis_rgn, - -(escape.drawable_rect.left + escape.dc_rect.left), - -(escape.drawable_rect.top + escape.dc_rect.top) ); - SelectVisRgn( dce->hdc, vis_rgn ); - DeleteObject( vis_rgn ); -} - - -/*********************************************************************** - * release_dce - */ -static void release_dce( struct dce *dce ) -{ - struct x11drv_escape_set_drawable escape; - - if (!dce->hwnd) return; /* already released */ - - if (dce->clip_rgn) DeleteObject( dce->clip_rgn ); - dce->clip_rgn = 0; - dce->hwnd = 0; - dce->flags &= DCX_CACHE; - - escape.code = X11DRV_SET_DRAWABLE; - escape.drawable = root_window; - escape.mode = IncludeInferiors; - escape.drawable_rect = virtual_screen_rect; - SetRect( &escape.dc_rect, 0, 0, virtual_screen_rect.right - virtual_screen_rect.left, - virtual_screen_rect.bottom - virtual_screen_rect.top ); - escape.fbconfig_id = 0; - escape.gl_drawable = 0; - escape.pixmap = 0; - ExtEscape( dce->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); -} - - -/*********************************************************************** - * delete_clip_rgn - */ -static void delete_clip_rgn( struct dce *dce ) -{ - if (!dce->clip_rgn) return; /* nothing to do */ - - dce->flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN); - DeleteObject( dce->clip_rgn ); - dce->clip_rgn = 0; - - /* make it dirty so that the vis rgn gets recomputed next time */ - SetHookFlags( dce->hdc, DCHF_INVALIDATEVISRGN ); -} - - -/*********************************************************************** - * 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_PTR)dce ); - - dce->hwnd = 0; - dce->clip_rgn = 0; - dce->flags = DCX_CACHE; - dce->class_ptr = NULL; - dce->count = 1; - - 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; - } - - /* store DCE handle in DC hook data field */ - - SetDCHook( dce->hdc, dc_hook, (DWORD_PTR)dce ); - - dce->hwnd = data->hwnd; - dce->clip_rgn = 0; - dce->flags = 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; - } - SetHookFlags( 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) - { - release_dce( dce ); - } - 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->count) WARN( "GetDC() without ReleaseDC() for window %p\n", data->hwnd ); - release_dce( dce ); - dce->count = 0; - } - LeaveCriticalSection( &dce_section ); -} - - -/*********************************************************************** - * 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->hwnd) 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 || hwndScope == GetDesktopWindow() || 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->count) - { - /* Don't bother with visible regions of unused DCEs */ - - TRACE("\tpurged %p dce [%p]\n", dce, dce->hwnd); - release_dce( dce ); - } - else - { - /* Set dirty bits in the hDC and DCE structs */ - - TRACE("\tfixed up %p dce [%p]\n", dce, dce->hwnd); - SetHookFlags( dce->hdc, DCHF_INVALIDATEVISRGN ); - } - } - } /* dce list */ - } -} - - -/*********************************************************************** - * X11DRV_GetDCEx (X11DRV.@) - * - * Unimplemented flags: DCX_LOCKWINDOWUPDATE - */ -HDC X11DRV_GetDCEx( HWND hwnd, HRGN hrgnClip, DWORD flags ) -{ - static const DWORD clip_flags = DCX_PARENTCLIP | DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW; - - struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); - struct dce *dce; - BOOL bUpdateVisRgn = TRUE; - HWND parent; - LONG window_style = GetWindowLongW( hwnd, GWL_STYLE ); - - TRACE("hwnd %p, hrgnClip %p, flags %08x\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; - } - } - - /* find a suitable DCE */ - - 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. - */ - EnterCriticalSection( &dce_section ); - LIST_FOR_EACH_ENTRY( dce, &dce_list, struct dce, entry ) - { - if ((dce->flags & DCX_CACHE) && !dce->count) - { - dceUnused = dce; - - if (!dce->hwnd) dceEmpty = dce; - else if ((dce->hwnd == hwnd) && !((dce->flags ^ flags) & clip_flags)) - { - TRACE("\tfound valid %p dce [%p], flags %08x\n", - dce, hwnd, dce->flags ); - bUpdateVisRgn = FALSE; - break; - } - } - } - - if (&dce->entry == &dce_list) /* nothing found */ - dce = dceEmpty ? dceEmpty : dceUnused; - - if (dce) dce->count = 1; - - LeaveCriticalSection( &dce_section ); - - /* if there's no dce empty or unused, allocate a new one */ - if (!dce) dce = alloc_cache_dce(); - if (!dce) return 0; - } - else - { - flags |= DCX_NORESETATTRS; - dce = data->dce; - if (dce->hwnd == hwnd) - { - TRACE("\tskipping hVisRgn update\n"); - bUpdateVisRgn = FALSE; /* updated automatically, via DCHook() */ - } - else - { - /* we should free dce->clip_rgn here, but Windows apparently doesn't */ - dce->flags &= ~(DCX_EXCLUDERGN | DCX_INTERSECTRGN); - dce->clip_rgn = 0; - } - } - - if (flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN)) - { - /* if the extra clip region has changed, get rid of the old one */ - if (dce->clip_rgn != hrgnClip || ((flags ^ dce->flags) & (DCX_INTERSECTRGN | DCX_EXCLUDERGN))) - delete_clip_rgn( dce ); - dce->clip_rgn = hrgnClip; - if (!dce->clip_rgn) dce->clip_rgn = CreateRectRgn( 0, 0, 0, 0 ); - dce->flags |= flags & (DCX_INTERSECTRGN | DCX_EXCLUDERGN); - bUpdateVisRgn = TRUE; - } - - dce->hwnd = hwnd; - dce->flags = (dce->flags & ~clip_flags) | (flags & clip_flags); - - if (SetHookFlags( dce->hdc, DCHF_VALIDATEVISRGN )) - bUpdateVisRgn = TRUE; /* DC was dirty */ - - if (bUpdateVisRgn) update_visible_region( dce ); - - if (!(flags & DCX_NORESETATTRS)) - { - RestoreDC( dce->hdc, 1 ); /* initial save level is always 1 */ - SaveDC( dce->hdc ); /* save the state again for next time */ - } - - TRACE("(%p,%p,0x%x): returning %p\n", hwnd, hrgnClip, flags, dce->hdc); - return dce->hdc; -} - - -/*********************************************************************** - * X11DRV_ReleaseDC (X11DRV.@) - */ -INT X11DRV_ReleaseDC( HWND hwnd, HDC hdc, BOOL end_paint ) -{ - struct dce *dce; - BOOL ret = FALSE; - - TRACE("%p %p\n", hwnd, hdc ); - - EnterCriticalSection( &dce_section ); - dce = (struct dce *)GetDCHook( hdc, NULL ); - if (dce && dce->count) - { - if (end_paint || (dce->flags & DCX_CACHE)) delete_clip_rgn( dce ); - if (dce->flags & DCX_CACHE) dce->count = 0; - ret = TRUE; - } - LeaveCriticalSection( &dce_section ); - return ret; -} - -/*********************************************************************** - * dc_hook - * - * See "Undoc. Windows" for hints (DC, SetDCHook, SetHookFlags).. - */ -static BOOL CALLBACK dc_hook( HDC hDC, WORD code, DWORD_PTR data, LPARAM lParam ) -{ - BOOL retv = TRUE; - struct dce *dce = (struct dce *)data; - - TRACE("hDC = %p, %u\n", hDC, code); - - if (!dce) return 0; - assert( 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->count) update_visible_region( dce ); - 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->count) - { - WARN("Application trying to delete a busy DC %p\n", dce->hdc); - 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 ); - if ((dce = (struct dce *)GetDCHook( hdc, NULL ))) hwnd = dce->hwnd; - LeaveCriticalSection( &dce_section ); - return hwnd; -} diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index fa6fac8d646..a3c11853728 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1468,8 +1468,6 @@ BOOL X11DRV_SetPixelFormat(X11DRV_PDEVICE *physDev, ERR("Couldn't set format of the window, returning failure\n"); return FALSE; } - - physDev->gl_drawable = X11DRV_get_gl_drawable(hwnd); } else if(physDev->bitmap) { if(!(value&GLX_PIXMAP_BIT)) { diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 9939d7e044e..9505103e44b 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -71,6 +71,8 @@ static const char visual_id_prop[] = "__wine_x11_visual_id"; extern int usexcomposite; +extern void WIN_invalidate_dce( HWND hwnd, const RECT *rect ); /* FIXME: to be removed */ + /*********************************************************************** * is_window_managed * @@ -471,7 +473,7 @@ done: wine_tsx11_lock(); XFlush( display ); wine_tsx11_unlock(); - invalidate_dce( hwnd, &data->window_rect ); + WIN_invalidate_dce( hwnd, NULL ); return TRUE; } @@ -542,7 +544,6 @@ static void sync_gl_drawable(Display *display, struct x11drv_win_data *data) SetPropA(data->hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable); SetPropA(data->hwnd, pixmap_prop, (HANDLE)data->pixmap); - invalidate_dce( data->hwnd, &data->window_rect ); } @@ -1307,7 +1308,6 @@ void X11DRV_DestroyWindow( HWND hwnd ) wine_tsx11_unlock(); } - free_window_dce( data ); destroy_whole_window( display, data ); destroy_icon_window( display, data ); @@ -1489,9 +1489,6 @@ struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd ) hwnd, data->whole_window, data->client_window, wine_dbgstr_rect( &data->window_rect ), wine_dbgstr_rect( &data->whole_rect ), wine_dbgstr_rect( &data->client_rect )); } - - /* get class or window DC if needed */ - alloc_window_dce( data ); return data; } @@ -1533,57 +1530,80 @@ Window X11DRV_get_client_window( HWND hwnd ) /*********************************************************************** - * X11DRV_get_fbconfig_id + * X11DRV_get_ic * - * Return the GLXFBConfig ID of the drawable used by the window for - * OpenGL rendering. This is 0 for windows without a pixel format set. + * Return the X input context associated with a window */ -XID X11DRV_get_fbconfig_id( HWND hwnd ) +XIC X11DRV_get_ic( HWND hwnd ) { struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); - if (!data) return (XID)GetPropA( hwnd, fbconfig_id_prop ); - return data->fbconfig_id; + if (!data) return 0; + return data->xic; } + /*********************************************************************** - * X11DRV_get_gl_drawable - * - * Return the GL drawable for this window. + * X11DRV_GetDC (X11DRV.@) */ -Drawable X11DRV_get_gl_drawable( HWND hwnd ) +void X11DRV_GetDC( HDC hdc, HWND hwnd, HWND top, const RECT *win_rect, + const RECT *top_rect, DWORD flags ) { + struct x11drv_escape_set_drawable escape; struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); - if (!data) return (Drawable)GetPropA( hwnd, gl_drawable_prop ); - return data->gl_drawable; -} + escape.code = X11DRV_SET_DRAWABLE; + escape.mode = IncludeInferiors; + escape.fbconfig_id = 0; + escape.gl_drawable = 0; + escape.pixmap = 0; -/*********************************************************************** - * X11DRV_get_gl_pixmap - * - * Return the Pixmap associated with the GL drawable (if any) for this window. - */ -Pixmap X11DRV_get_gl_pixmap( HWND hwnd ) -{ - struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); + if (top == hwnd && data && IsIconic( hwnd ) && data->icon_window) + { + escape.drawable = data->icon_window; + } + else if (top == hwnd && (flags & DCX_WINDOW)) + { + escape.drawable = data ? data->whole_window : X11DRV_get_whole_window( hwnd ); + } + else + { + escape.drawable = X11DRV_get_client_window( top ); + escape.fbconfig_id = data ? data->fbconfig_id : (XID)GetPropA( hwnd, fbconfig_id_prop ); + escape.gl_drawable = data ? data->gl_drawable : (Drawable)GetPropA( hwnd, gl_drawable_prop ); + escape.pixmap = data ? data->pixmap : (Pixmap)GetPropA( hwnd, pixmap_prop ); + } - if (!data) return (Pixmap)GetPropA( hwnd, pixmap_prop ); - return data->pixmap; + escape.dc_rect.left = win_rect->left - top_rect->left; + escape.dc_rect.top = win_rect->top - top_rect->top; + escape.dc_rect.right = win_rect->right - top_rect->left; + escape.dc_rect.bottom = win_rect->bottom - top_rect->top; + escape.drawable_rect.left = top_rect->left; + escape.drawable_rect.top = top_rect->top; + escape.drawable_rect.right = top_rect->right; + escape.drawable_rect.bottom = top_rect->bottom; + + ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); } /*********************************************************************** - * X11DRV_get_ic - * - * Return the X input context associated with a window + * X11DRV_ReleaseDC (X11DRV.@) */ -XIC X11DRV_get_ic( HWND hwnd ) +void X11DRV_ReleaseDC( HWND hwnd, HDC hdc ) { - struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); - - if (!data) return 0; - return data->xic; + struct x11drv_escape_set_drawable escape; + + escape.code = X11DRV_SET_DRAWABLE; + escape.drawable = root_window; + escape.mode = IncludeInferiors; + escape.drawable_rect = virtual_screen_rect; + SetRect( &escape.dc_rect, 0, 0, virtual_screen_rect.right - virtual_screen_rect.left, + virtual_screen_rect.bottom - virtual_screen_rect.top ); + escape.fbconfig_id = 0; + escape.gl_drawable = 0; + escape.pixmap = 0; + ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); } @@ -1708,7 +1728,6 @@ int X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) if ((data = X11DRV_get_win_data( hwnd ))) { sync_window_region( thread_display(), data, hrgn ); - invalidate_dce( hwnd, &data->window_rect ); } else if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId()) { diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 36b83d7bbbf..74ddb660b76 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -96,11 +96,11 @@ @ cdecl EnumClipboardFormats(long) X11DRV_EnumClipboardFormats @ cdecl GetClipboardData(long ptr ptr) X11DRV_GetClipboardData @ cdecl GetClipboardFormatName(long ptr long) X11DRV_GetClipboardFormatName -@ cdecl GetDCEx(long long long) X11DRV_GetDCEx +@ cdecl GetDC(long long long ptr ptr long) X11DRV_GetDC @ cdecl IsClipboardFormatAvailable(long) X11DRV_IsClipboardFormatAvailable @ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) X11DRV_MsgWaitForMultipleObjectsEx @ cdecl RegisterClipboardFormat(wstr) X11DRV_RegisterClipboardFormat -@ cdecl ReleaseDC(long long long) X11DRV_ReleaseDC +@ cdecl ReleaseDC(long long) X11DRV_ReleaseDC @ cdecl ScrollDC(long long long ptr ptr long ptr) X11DRV_ScrollDC @ cdecl SetClipboardData(long long long long) X11DRV_SetClipboardData @ cdecl SetFocus(long) X11DRV_SetFocus @@ -112,7 +112,6 @@ @ 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 diff --git a/dlls/winex11.drv/winpos.c b/dlls/winex11.drv/winpos.c index 08ffc484089..13aec41e238 100644 --- a/dlls/winex11.drv/winpos.c +++ b/dlls/winex11.drv/winpos.c @@ -141,15 +141,11 @@ void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style ) new_style = GetWindowLongW( hwnd, GWL_STYLE ); changed = new_style ^ old_style; - if (changed & WS_VISIBLE) + if ((changed & WS_VISIBLE) && (new_style & WS_VISIBLE)) { - data = X11DRV_get_win_data( hwnd ); - if (data) invalidate_dce( hwnd, &data->window_rect ); - /* we don't unmap windows, that causes trouble with the window manager */ - if (!(new_style & WS_VISIBLE)) return; - - if (!data && !(data = X11DRV_create_win_data( hwnd ))) return; + if (!(data = X11DRV_get_win_data( hwnd )) && + !(data = X11DRV_create_win_data( hwnd ))) return; if (data->whole_window && X11DRV_is_window_rect_mapped( &data->window_rect )) { @@ -361,15 +357,6 @@ void X11DRV_SetWindowPos( HWND hwnd, HWND insert_after, UINT swp_flags, SERVER_END_REQ; } - /* invalidate DCEs */ - if ((((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) && (new_style & WS_VISIBLE)) || - (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW))) - { - RECT rect; - UnionRect( &rect, rectWindow, &old_window_rect ); - invalidate_dce( hwnd, &rect ); - } - TRACE( "win %p window %s client %s style %08x\n", hwnd, wine_dbgstr_rect(rectWindow), wine_dbgstr_rect(rectClient), new_style ); @@ -788,8 +775,6 @@ void X11DRV_MapNotify( HWND hwnd, XEvent *event ) OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top ); X11DRV_X_to_window_rect( data, &rect ); - invalidate_dce( hwnd, &data->window_rect ); - if (win->flags & WIN_RESTORE_MAX) style |= WS_MAXIMIZE; WIN_SetStyle( hwnd, style, WS_MINIMIZE ); WIN_ReleasePtr( win ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index de77925213b..8f80452d182 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -492,12 +492,6 @@ struct x11drv_escape_set_drawable Pixmap pixmap; /* Pixmap for a GLXPixmap gl_drawable */ }; -struct x11drv_escape_set_dce -{ - enum x11drv_escape_codes code; /* escape code (X11DRV_SET_DRAWABLE) */ - struct dce *dce; /* pointer to DCE (opaque ptr for GDI) */ -}; - /************************************************************************** * X11 USER driver */ @@ -676,7 +670,6 @@ struct x11drv_win_data BOOL managed : 1; /* is window managed? */ BOOL mapped : 1; /* is window mapped? (in either normal or iconic state) */ DWORD wm_state; /* bit mask of active x11drv_wm_state values */ - struct dce *dce; /* DCE for CS_OWNDC or CS_CLASSDC windows */ unsigned int lock_changes; /* lock count for X11 change requests */ HBITMAP hWMIconBitmap; HBITMAP hWMIconMask; @@ -686,9 +679,6 @@ extern struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd ); extern struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd ); extern Window X11DRV_get_whole_window( HWND hwnd ); extern Window X11DRV_get_client_window( HWND hwnd ); -extern XID X11DRV_get_fbconfig_id( HWND hwnd ); -extern Drawable X11DRV_get_gl_drawable( HWND hwnd ); -extern Pixmap X11DRV_get_gl_pixmap( HWND hwnd ); extern BOOL X11DRV_is_window_rect_mapped( const RECT *rect ); extern XIC X11DRV_get_ic( HWND hwnd ); extern BOOL X11DRV_set_win_format( HWND hwnd, XID fbconfig ); @@ -699,10 +689,6 @@ extern void mark_drawable_dirty( Drawable old, Drawable new ); extern Drawable create_glxpixmap( Display *display, XVisualInfo *vis, Pixmap parent ); extern void flush_gl_drawable( X11DRV_PDEVICE *physDev ); -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; diff --git a/include/win.h b/include/win.h index baa8c6d7345..4ed39f6dd23 100644 --- a/include/win.h +++ b/include/win.h @@ -38,6 +38,7 @@ typedef struct tagWND HWND parent; /* Window parent */ HWND owner; /* Window owner */ struct tagCLASS *class; /* Window class */ + struct dce *dce; /* DCE pointer */ WNDPROC winproc; /* Window procedure */ DWORD dwMagic; /* Magic number (must be WND_MAGIC) */ DWORD tid; /* Owner thread id */ -- 2.11.4.GIT