diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in index c7a32bc7c6d..b8d88257064 100644 --- a/dlls/user/Makefile.in +++ b/dlls/user/Makefile.in @@ -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 \ diff --git a/dlls/user/painting.c b/dlls/user/painting.c index 62993f44c66..d0f568db0b4 100644 --- a/dlls/user/painting.c +++ b/dlls/user/painting.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.@) */ diff --git a/dlls/user/user16.c b/dlls/user/user16.c index 87db9251703..f5c6df99c7c 100644 --- a/dlls/user/user16.c +++ b/dlls/user/user16.c @@ -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) */ diff --git a/dlls/user/user32.spec b/dlls/user/user32.spec index c9a6efb7074..18eff6f40e1 100644 --- a/dlls/user/user32.spec +++ b/dlls/user/user32.spec @@ -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) diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c index c99d4aa1a36..70be706ffd7 100644 --- a/dlls/user/user_main.c +++ b/dlls/user/user_main.c @@ -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; diff --git a/dlls/user/user_private.h b/dlls/user/user_private.h index 43e849a3a0f..bda67c016be 100644 --- a/dlls/user/user_private.h +++ b/dlls/user/user_private.h @@ -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; diff --git a/dlls/x11drv/Makefile.in b/dlls/x11drv/Makefile.in index c2a45d7904a..c708b783e04 100644 --- a/dlls/x11drv/Makefile.in +++ b/dlls/x11drv/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ clipboard.c \ clipping.c \ codepage.c \ + dce.c \ desktop.c \ dga2.c \ dib.c \ diff --git a/dlls/x11drv/dce.c b/dlls/x11drv/dce.c new file mode 100644 index 00000000000..492c3555010 --- /dev/null +++ b/dlls/x11drv/dce.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 +#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; +} diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c index b4a7fe47892..ff8175a2541 100644 --- a/dlls/x11drv/window.c +++ b/dlls/x11drv/window.c @@ -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 diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index 5a941c1fa75..5f2abc5bc6f 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -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 ); diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h index e6b4c6a9f71..b04594667a8 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -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; diff --git a/dlls/x11drv/x11drv.spec b/dlls/x11drv/x11drv.spec index ea4460a9ad5..3e4a44456e9 100644 --- a/dlls/x11drv/x11drv.spec +++ b/dlls/x11drv/x11drv.spec @@ -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 diff --git a/include/dce.h b/include/dce.h deleted file mode 100644 index bdbbee0b442..00000000000 --- a/include/dce.h +++ /dev/null @@ -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 - -/* 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 */ diff --git a/include/win.h b/include/win.h index 78954794ea3..1aed8eba936 100644 --- a/include/win.h +++ b/include/win.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 */ diff --git a/windows/class.c b/windows/class.c index 40b5d303832..759b9ece50a 100644 --- a/windows/class.c +++ b/windows/class.c @@ -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; } diff --git a/windows/dce.c b/windows/dce.c deleted file mode 100644 index 832d1e73ee4..00000000000 --- a/windows/dce.c +++ /dev/null @@ -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 -#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; -} diff --git a/windows/nonclient.c b/windows/nonclient.c index 8ca949fe960..6072d13e550 100644 --- a/windows/nonclient.c +++ b/windows/nonclient.c @@ -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" diff --git a/windows/win.c b/windows/win.c index f3a2dca9666..f02b9142785 100644 --- a/windows/win.c +++ b/windows/win.c @@ -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) ||