From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 4 ++-- dlls/winex11.drv/vulkan.c | 2 +- dlls/winex11.drv/window.c | 24 +++++++++++------------- dlls/winex11.drv/x11drv.h | 2 +- 4 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index e68bdd59ddb..5cacb1d9649 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1121,7 +1121,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct glx_pixel gl->colormap = XCreateColormap( gdi_display, get_dummy_parent(), visual->visual, (visual->class == PseudoColor || visual->class == GrayScale || visual->class == DirectColor) ? AllocAll : AllocNone ); - gl->window = create_client_window( hwnd, visual, gl->colormap ); + gl->window = create_client_window( hwnd, visual, gl->colormap, FALSE ); if (gl->window) gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); TRACE( "%p created client %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); @@ -1133,7 +1133,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct glx_pixel gl->colormap = XCreateColormap( gdi_display, get_dummy_parent(), visual->visual, (visual->class == PseudoColor || visual->class == GrayScale || visual->class == DirectColor) ? AllocAll : AllocNone ); - gl->window = create_client_window( hwnd, visual, gl->colormap ); + gl->window = create_client_window( hwnd, visual, gl->colormap, TRUE ); if (gl->window) { gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 85993bc517a..99409f988c8 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -81,7 +81,7 @@ static VkResult X11DRV_vulkan_surface_create( HWND hwnd, VkInstance instance, Vk return VK_ERROR_INCOMPATIBLE_DRIVER; }
- if (!(info.window = create_client_window( hwnd, &default_visual, default_colormap ))) + if (!(info.window = create_client_window( hwnd, &default_visual, default_colormap, FALSE ))) { ERR("Failed to allocate client window for hwnd=%p\n", hwnd); return VK_ERROR_OUT_OF_HOST_MEMORY; diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1902d060bba..de4e93b54ee 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1596,12 +1596,12 @@ void destroy_client_window( HWND hwnd, Window client_window ) /********************************************************************** * create_client_window */ -Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap ) +Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap, BOOL offscreen ) { Window dummy_parent = get_dummy_parent(); struct x11drv_win_data *data = get_win_data( hwnd ); XSetWindowAttributes attr; - Window ret; + Window client_window, parent_window; int x, y, cx, cy;
if (!data) @@ -1614,7 +1614,7 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo data->rects.window = data->rects.visible = data->rects.client; }
- detach_client_window( data, data->client_window ); + if (!offscreen) detach_client_window( data, data->client_window );
attr.colormap = colormap; attr.bit_gravity = NorthWestGravity; @@ -1628,23 +1628,21 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo cy = min( max( 1, data->rects.client.bottom - data->rects.client.top ), 65535 );
XSync( gdi_display, False ); /* make sure whole_window is known from gdi_display */ - ret = data->client_window = XCreateWindow( gdi_display, - data->whole_window ? data->whole_window : dummy_parent, - x, y, cx, cy, 0, default_visual.depth, InputOutput, - visual->visual, CWBitGravity | CWWinGravity | - CWBackingStore | CWColormap | CWBorderPixel, &attr ); - if (data->client_window) - { - XMapWindow( gdi_display, data->client_window ); - if (data->whole_window) + if (offscreen || !(parent_window = data->whole_window)) parent_window = dummy_parent; + if ((client_window = XCreateWindow( gdi_display, parent_window, x, y, cx, cy, 0, default_visual.depth, InputOutput, visual->visual, + CWBitGravity | CWWinGravity | CWBackingStore | CWColormap | CWBorderPixel, &attr ))) + { + XMapWindow( gdi_display, client_window ); + if (!offscreen) { + data->client_window = client_window; XFlush( gdi_display ); /* make sure client_window is created for XSelectInput */ client_window_events_enable( data, data->client_window ); } TRACE( "%p xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); } release_win_data( data ); - return ret; + return client_window; }
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index e904087f262..88560a9c9e0 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -642,7 +642,7 @@ extern void update_user_time( Time time ); extern void read_net_wm_states( Display *display, struct x11drv_win_data *data ); extern void update_net_wm_states( struct x11drv_win_data *data ); extern void make_window_embedded( struct x11drv_win_data *data ); -extern Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap ); +extern Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap, BOOL offscreen ); extern void detach_client_window( struct x11drv_win_data *data, Window client_window ); extern void destroy_client_window( HWND hwnd, Window client_window ); extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 2 +- dlls/winex11.drv/window.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 5cacb1d9649..3fcad8a4a00 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1098,7 +1098,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct glx_pixel RECT rect; int width, height;
- NtUserGetClientRect( hwnd, &rect, get_win_monitor_dpi( hwnd ) ); + NtUserGetClientRect( hwnd, &rect, NtUserGetDpiForWindow( hwnd ) ); width = min( max( 1, rect.right ), 65535 ); height = min( max( 1, rect.bottom ), 65535 );
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index de4e93b54ee..3774234d45a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1603,6 +1603,7 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo XSetWindowAttributes attr; Window client_window, parent_window; int x, y, cx, cy; + RECT client_rect;
if (!data) { @@ -1624,8 +1625,10 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo
x = data->rects.client.left - data->rects.visible.left; y = data->rects.client.top - data->rects.visible.top; - cx = min( max( 1, data->rects.client.right - data->rects.client.left ), 65535 ); - cy = min( max( 1, data->rects.client.bottom - data->rects.client.top ), 65535 ); + + NtUserGetClientRect( hwnd, &client_rect, NtUserGetDpiForWindow( hwnd ) ); + cx = min( max( 1, client_rect.right - client_rect.left ), 65535 ); + cy = min( max( 1, client_rect.bottom - client_rect.top ), 65535 );
XSync( gdi_display, False ); /* make sure whole_window is known from gdi_display */ if (offscreen || !(parent_window = data->whole_window)) parent_window = dummy_parent;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 84 ++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 45 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 3fcad8a4a00..f8e220df1f0 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1822,58 +1822,57 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de return TRUE; }
+static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOOL flush ) +{ + struct x11drv_escape_flush_gl_drawable escape = + { + .code = X11DRV_FLUSH_GL_DRAWABLE, + .flush = flush, + }; + Drawable drawable; + + if (!gl) return; + switch (gl->type) + { + case DC_GL_PIXMAP_WIN: drawable = gl->pixmap; break; + case DC_GL_CHILD_WIN: drawable = gl->window; break; + default: drawable = 0; break; + } + if (!(escape.gl_drawable = drawable)) return; + + NtGdiExtEscape( hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); +} + static void wglFinish(void) { - struct x11drv_escape_flush_gl_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; + HWND hwnd = NtUserWindowFromDC( ctx->hdc );
- escape.code = X11DRV_FLUSH_GL_DRAWABLE; - escape.gl_drawable = 0; - escape.flush = FALSE; - - if ((gl = get_gl_drawable( NtUserWindowFromDC( ctx->hdc ), 0 ))) + if (!(gl = get_gl_drawable( hwnd, 0 ))) pglFinish(); + else { - switch (gl->type) - { - case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break; - case DC_GL_CHILD_WIN: escape.gl_drawable = gl->window; break; - default: break; - } sync_context(ctx); + pglFinish(); + present_gl_drawable( hwnd, ctx->hdc, gl, FALSE ); release_gl_drawable( gl ); } - - pglFinish(); - if (escape.gl_drawable) - NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); }
static void wglFlush(void) { - struct x11drv_escape_flush_gl_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; + HWND hwnd = NtUserWindowFromDC( ctx->hdc );
- escape.code = X11DRV_FLUSH_GL_DRAWABLE; - escape.gl_drawable = 0; - escape.flush = FALSE; - - if ((gl = get_gl_drawable( NtUserWindowFromDC( ctx->hdc ), 0 ))) + if (!(gl = get_gl_drawable( hwnd, 0 ))) pglFlush(); + else { - switch (gl->type) - { - case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break; - case DC_GL_CHILD_WIN: escape.gl_drawable = gl->window; break; - default: break; - } sync_context(ctx); + pglFlush(); + present_gl_drawable( hwnd, ctx->hdc, gl, FALSE ); release_gl_drawable( gl ); } - - pglFlush(); - if (escape.gl_drawable) - NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); }
static const GLubyte *wglGetString(GLenum name) @@ -2731,18 +2730,15 @@ static void X11DRV_WineGL_LoadExtensions(void) */ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) { - struct x11drv_escape_flush_gl_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; INT64 ust, msc, sbc, target_sbc = 0; + HWND hwnd = NtUserWindowFromDC( hdc ); + Drawable drawable = 0;
TRACE("(%p)\n", hdc);
- escape.code = X11DRV_FLUSH_GL_DRAWABLE; - escape.gl_drawable = 0; - escape.flush = !pglXWaitForSbcOML; - - if (!(gl = get_gl_drawable( NtUserWindowFromDC( hdc ), hdc ))) + if (!(gl = get_gl_drawable( hwnd, hdc ))) { RtlSetLastWin32Error( ERROR_INVALID_HANDLE ); return FALSE; @@ -2760,7 +2756,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) { case DC_GL_PIXMAP_WIN: if (ctx) sync_context( ctx ); - escape.gl_drawable = gl->pixmap; + drawable = gl->pixmap; if (ctx && pglXCopySubBufferMESA) { /* (glX)SwapBuffers has an implicit glFlush effect, however * GLX_MESA_copy_sub_buffer doesn't. Make sure GL is flushed before @@ -2781,10 +2777,10 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) case DC_GL_WINDOW: case DC_GL_CHILD_WIN: if (ctx) sync_context( ctx ); - if (gl->type == DC_GL_CHILD_WIN) escape.gl_drawable = gl->window; + if (gl->type == DC_GL_CHILD_WIN) drawable = gl->window; /* fall through */ default: - if (ctx && escape.gl_drawable && pglXSwapBuffersMscOML) + if (ctx && drawable && pglXSwapBuffersMscOML) { pglFlush(); target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); @@ -2794,13 +2790,11 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) break; }
- if (ctx && escape.gl_drawable && pglXWaitForSbcOML) + if (ctx && drawable && pglXWaitForSbcOML) pglXWaitForSbcOML( gdi_display, gl->drawable, target_sbc, &ust, &msc, &sbc );
+ present_gl_drawable( hwnd, ctx ? ctx->hdc : hdc, gl, !pglXWaitForSbcOML ); release_gl_drawable( gl ); - - if (escape.gl_drawable) - NtGdiExtEscape( ctx ? ctx->hdc : hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/opengl.c | 52 ++++++++++++++++++++++++++++++++++----- dlls/winex11.drv/x11drv.h | 3 +-- 3 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index fa477a4de6b..5b3ff6d379c 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -240,6 +240,7 @@ static INT X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_d { struct x11drv_escape_get_drawable *data = out_data; data->drawable = physDev->drawable; + data->dc_rect = physDev->dc_rect; return TRUE; } break; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index f8e220df1f0..5f40f28de3d 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1822,13 +1822,34 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de return TRUE; }
-static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOOL flush ) +static void set_dc_drawable( HDC hdc, Drawable drawable, const RECT *rect, int mode ) { - struct x11drv_escape_flush_gl_drawable escape = + struct x11drv_escape_set_drawable escape = { - .code = X11DRV_FLUSH_GL_DRAWABLE, - .flush = flush, + .code = X11DRV_SET_DRAWABLE, + .drawable = drawable, + .dc_rect = *rect, + .mode = mode, }; + NtGdiExtEscape( hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); +} + +static Drawable get_dc_drawable( HDC hdc, RECT *rect ) +{ + struct x11drv_escape_get_drawable escape = {.code = X11DRV_GET_DRAWABLE}; + NtGdiExtEscape( hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, sizeof(escape), (LPSTR)&escape ); + *rect = escape.dc_rect; + return escape.drawable; +} + +static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOOL flush ) +{ + static const WCHAR displayW[] = {'D','I','S','P','L','A','Y'}; + static HDC hdc_src; + + UNICODE_STRING device_str = RTL_CONSTANT_STRING(displayW); + HWND toplevel = NtUserGetAncestor( hwnd, GA_ROOT ); + RECT rect_dst, rect_src, rect; Drawable drawable;
if (!gl) return; @@ -1838,9 +1859,28 @@ static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOO case DC_GL_CHILD_WIN: drawable = gl->window; break; default: drawable = 0; break; } - if (!(escape.gl_drawable = drawable)) return; + if (!drawable) return;
- NtGdiExtEscape( hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); + if (flush) XFlush( gdi_display ); + + NtUserGetClientRect( hwnd, &rect_src, NtUserGetDpiForWindow( hwnd ) ); + OffsetRect( &rect_src, -rect_src.left, -rect_src.top ); + + NtUserGetClientRect( hwnd, &rect_dst, get_win_monitor_dpi( hwnd ) ); + NtUserMapWindowPoints( hwnd, toplevel, (POINT *)&rect_dst, 2, get_win_monitor_dpi( hwnd ) ); + + pthread_mutex_lock( &context_mutex ); + + if (!hdc_src && !(hdc_src = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ))) goto done; + + if (get_dc_drawable( hdc_src, &rect ) != drawable || !EqualRect( &rect, &rect_src )) + set_dc_drawable( hdc_src, drawable, &rect_src, IncludeInferiors ); + + NtGdiStretchBlt( hdc, 0, 0, rect_dst.right - rect_dst.left, rect_dst.bottom - rect_dst.top, + hdc_src, 0, 0, rect_src.right, rect_src.bottom, SRCCOPY, 0 ); + +done: + pthread_mutex_unlock( &context_mutex ); }
static void wglFinish(void) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 88560a9c9e0..b966b685ec4 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -351,8 +351,7 @@ struct x11drv_escape_get_drawable { enum x11drv_escape_codes code; /* escape code (X11DRV_GET_DRAWABLE) */ Drawable drawable; /* X drawable */ - Drawable gl_drawable; /* GL drawable */ - int pixel_format; /* internal GL pixel format */ + RECT dc_rect; /* DC rectangle relative to drawable */ };
struct x11drv_escape_flush_gl_drawable
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/init.c | 16 ---------------- dlls/winex11.drv/x11drv.h | 8 -------- 2 files changed, 24 deletions(-)
diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 5b3ff6d379c..ea19be92b74 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -244,22 +244,6 @@ static INT X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOID in_d return TRUE; } break; - case X11DRV_FLUSH_GL_DRAWABLE: - if (in_count >= sizeof(struct x11drv_escape_flush_gl_drawable)) - { - const struct x11drv_escape_flush_gl_drawable *data = in_data; - RECT rect = physDev->dc_rect; - - OffsetRect( &rect, -physDev->dc_rect.left, -physDev->dc_rect.top ); - if (data->flush) XFlush( gdi_display ); - XSetFunction( gdi_display, physDev->gc, GXcopy ); - XCopyArea( gdi_display, data->gl_drawable, physDev->drawable, physDev->gc, - 0, 0, rect.right, rect.bottom, - physDev->dc_rect.left, physDev->dc_rect.top ); - add_device_bounds( physDev, &rect ); - return TRUE; - } - break; case X11DRV_START_EXPOSURES: XSetGraphicsExposures( gdi_display, physDev->gc, True ); physDev->exposures = 0; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index b966b685ec4..2595720ab9b 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -336,7 +336,6 @@ enum x11drv_escape_codes X11DRV_GET_DRAWABLE, /* get current drawable for a DC */ X11DRV_START_EXPOSURES, /* start graphics exposures */ X11DRV_END_EXPOSURES, /* end graphics exposures */ - X11DRV_FLUSH_GL_DRAWABLE /* flush changes made to the gl drawable */ };
struct x11drv_escape_set_drawable @@ -354,13 +353,6 @@ struct x11drv_escape_get_drawable RECT dc_rect; /* DC rectangle relative to drawable */ };
-struct x11drv_escape_flush_gl_drawable -{ - enum x11drv_escape_codes code; /* escape code (X11DRV_FLUSH_GL_DRAWABLE) */ - Drawable gl_drawable; /* GL drawable */ - BOOL flush; /* flush X11 before copying */ -}; - /************************************************************************** * X11 USER driver */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 61 +++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 5f40f28de3d..dac856e992e 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1086,6 +1086,16 @@ static GLXContext create_glxcontext(Display *display, struct wgl_context *contex return ctx; }
+static BOOL needs_offscreen_rendering( HWND hwnd, BOOL known_child ) +{ + if (NtUserGetDpiForWindow( hwnd ) != get_win_monitor_dpi( hwnd )) return TRUE; + + if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && + NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) + return FALSE; /* childless top-level window */ + + return TRUE; +}
/*********************************************************************** * create_gl_drawable @@ -1114,8 +1124,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct glx_pixel gl->hwnd = hwnd; gl->mutable_pf = mutable_pf;
- if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && - NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) /* childless top-level window */ + if (!needs_offscreen_rendering( hwnd, known_child )) { gl->type = DC_GL_WINDOW; gl->colormap = XCreateColormap( gdi_display, get_dummy_parent(), visual->visual, @@ -1842,15 +1851,49 @@ static Drawable get_dc_drawable( HDC hdc, RECT *rect ) return escape.drawable; }
+static HRGN get_dc_monitor_region( HWND hwnd, HDC hdc ) +{ + RGNDATA *data; + UINT i, size; + HRGN region; + POINT pt; + + if (!(region = NtGdiCreateRectRgn( 0, 0, 0, 0 ))) return 0; + if (NtGdiGetRandomRgn( hdc, region, SYSRGN ) <= 0) goto failed; + if (!(size = NtGdiGetRegionData( region, 0, NULL ))) goto failed; + if (!(data = malloc( size ))) goto failed; + NtGdiGetRegionData( region, size, data ); + NtGdiDeleteObjectApp( region ); + + NtGdiGetDCPoint( hdc, NtGdiGetDCOrg, &pt ); + NtUserLogicalToPerMonitorDPIPhysicalPoint( hwnd, &pt ); + for (i = 0; i < data->rdh.nCount; i++) + { + RECT *rect = (RECT *)data->Buffer + i; + NtUserLogicalToPerMonitorDPIPhysicalPoint( hwnd, (POINT *)&rect->left ); + NtUserLogicalToPerMonitorDPIPhysicalPoint( hwnd, (POINT *)&rect->right ); + OffsetRect( rect, -pt.x, -pt.y ); + } + + region = NtGdiExtCreateRegion( NULL, size, data ); + free( data ); + return region; + +failed: + NtGdiDeleteObjectApp( region ); + return 0; +} + static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOOL flush ) { static const WCHAR displayW[] = {'D','I','S','P','L','A','Y'}; - static HDC hdc_src; + static HDC hdc_src, hdc_dst;
UNICODE_STRING device_str = RTL_CONSTANT_STRING(displayW); HWND toplevel = NtUserGetAncestor( hwnd, GA_ROOT ); RECT rect_dst, rect_src, rect; - Drawable drawable; + Drawable window, drawable; + HRGN region;
if (!gl) return; switch (gl->type) @@ -1860,6 +1903,8 @@ static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOO default: drawable = 0; break; } if (!drawable) return; + window = get_dc_drawable( hdc, &rect ); + region = get_dc_monitor_region( hwnd, hdc );
if (flush) XFlush( gdi_display );
@@ -1872,15 +1917,21 @@ static void present_gl_drawable( HWND hwnd, HDC hdc, struct gl_drawable *gl, BOO pthread_mutex_lock( &context_mutex );
if (!hdc_src && !(hdc_src = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ))) goto done; + if (!hdc_dst && !(hdc_dst = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ))) goto done;
if (get_dc_drawable( hdc_src, &rect ) != drawable || !EqualRect( &rect, &rect_src )) set_dc_drawable( hdc_src, drawable, &rect_src, IncludeInferiors ); + if (get_dc_drawable( hdc_dst, &rect ) != window || !EqualRect( &rect, &rect_dst )) + set_dc_drawable( hdc_dst, window, &rect_dst, ClipByChildren ); + if (region) NtGdiExtSelectClipRgn( hdc_dst, region, RGN_COPY );
- NtGdiStretchBlt( hdc, 0, 0, rect_dst.right - rect_dst.left, rect_dst.bottom - rect_dst.top, + NtGdiStretchBlt( hdc_dst, 0, 0, rect_dst.right - rect_dst.left, rect_dst.bottom - rect_dst.top, hdc_src, 0, 0, rect_src.right, rect_src.bottom, SRCCOPY, 0 );
done: pthread_mutex_unlock( &context_mutex ); + + if (region) NtGdiDeleteObjectApp( region ); }
static void wglFinish(void)