mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-06 03:28:09 +02:00
win32: Fix multi-monitor virtual desktop with negative monitor coords
Under Win32, when you have a multiple-monitor setup, Windows creates a 'virtual desktop', which is a rectangle surface that extends across all monitors. The primary monitor always starts with the top-left corner at coordinate (0,0). If you have any other monitors which extend to the left or above the primary monitor, the virtual desktop's top-left corner will actually have coordinates which are negative. This creates an issue in Cairo with the desktop DC, i.e. when you use a DC from the function GetDC(NULL). The same thing can occur with other third party libraries like GTK, when you access the Cairo surface from the root window. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=100793 Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
This commit is contained in:
parent
a8571a3030
commit
4d07b57c16
2 changed files with 56 additions and 4 deletions
|
|
@ -325,6 +325,8 @@ _cairo_win32_display_surface_create_for_dc (HDC original_dc,
|
|||
surface->win32.extents.y = 0;
|
||||
surface->win32.extents.width = width;
|
||||
surface->win32.extents.height = height;
|
||||
surface->win32.x_ofs = 0;
|
||||
surface->win32.y_ofs = 0;
|
||||
|
||||
surface->initial_clip_rgn = NULL;
|
||||
surface->had_simple_clip = FALSE;
|
||||
|
|
@ -466,7 +468,8 @@ _cairo_win32_display_surface_map_to_image (void *abstract_sur
|
|||
surface->win32.extents.width,
|
||||
surface->win32.extents.height,
|
||||
surface->win32.dc,
|
||||
surface->win32.extents.x, surface->win32.extents.y,
|
||||
surface->win32.extents.x + surface->win32.x_ofs, /* Handling multi-monitor... */
|
||||
surface->win32.extents.y + surface->win32.y_ofs, /* ... setup on Win32 */
|
||||
SRCCOPY)) {
|
||||
status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
|
||||
goto err;
|
||||
|
|
@ -544,11 +547,12 @@ _cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
|
|||
|
||||
if (damage->status) {
|
||||
if (!BitBlt (surface->win32.dc,
|
||||
0, 0,
|
||||
surface->win32.extents.x + surface->win32.x_ofs, /* Handling multi-monitor... */
|
||||
surface->win32.extents.y + surface->win32.y_ofs, /* ... setup on Win32 */
|
||||
surface->win32.extents.width,
|
||||
surface->win32.extents.height,
|
||||
fallback->win32.dc,
|
||||
0, 0,
|
||||
surface->win32.extents.x, surface->win32.extents.y,
|
||||
SRCCOPY))
|
||||
status = _cairo_win32_print_gdi_error (__FUNCTION__);
|
||||
} else if (damage->region) {
|
||||
|
|
@ -561,7 +565,8 @@ _cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
|
|||
rect.x, rect.y,
|
||||
rect.width, rect.height));
|
||||
if (!BitBlt (surface->win32.dc,
|
||||
rect.x, rect.y,
|
||||
rect.x + surface->win32.x_ofs, /* Handling multi-monitor... */
|
||||
rect.y + surface->win32.y_ofs, /* ... setup on Win32 */
|
||||
rect.width, rect.height,
|
||||
fallback->win32.dc,
|
||||
rect.x, rect.y,
|
||||
|
|
@ -628,6 +633,35 @@ _cairo_win32_save_initial_clip (HDC hdc, cairo_win32_display_surface_t *surface)
|
|||
surface->win32.extents.width = rect.right - rect.left;
|
||||
surface->win32.extents.height = rect.bottom - rect.top;
|
||||
|
||||
/* On multi-monitor setup, under Windows, the primary monitor always
|
||||
* have origin (0,0). Any monitors that extends to the left or above
|
||||
* will have coordinates in the negative range. Take this into
|
||||
* account, by forcing our Win32 surface to start at extent (0,0) and
|
||||
* using a device offset. Cairo does not handle extents with negative
|
||||
* offsets.
|
||||
*/
|
||||
surface->win32.x_ofs = 0;
|
||||
surface->win32.y_ofs = 0;
|
||||
if ((surface->win32.extents.x < 0) ||
|
||||
(surface->win32.extents.y < 0)) {
|
||||
/* Negative offsets occurs for (and ONLY for) the desktop DC (virtual
|
||||
* desktop), when a monitor extend to the left or above the primary
|
||||
* monitor.
|
||||
*
|
||||
* More info @ https://www.microsoft.com/msj/0697/monitor/monitor.aspx
|
||||
*
|
||||
* Note that any other DC, including memory DC created with
|
||||
* CreateCompatibleDC(<virtual desktop DC>) will have extents in the
|
||||
* positive range. This will be taken into account later when we perform
|
||||
* raster operations between the DC (may have to perform offset
|
||||
* translation).
|
||||
*/
|
||||
surface->win32.x_ofs = surface->win32.extents.x;
|
||||
surface->win32.y_ofs = surface->win32.extents.y;
|
||||
surface->win32.extents.x = 0;
|
||||
surface->win32.extents.y = 0;
|
||||
}
|
||||
|
||||
surface->initial_clip_rgn = NULL;
|
||||
surface->had_simple_clip = FALSE;
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,24 @@ typedef struct _cairo_win32_surface {
|
|||
* that match bounds of the clipped region.
|
||||
*/
|
||||
cairo_rectangle_int_t extents;
|
||||
|
||||
/* Offset added to extents, used when the extents start with a negative
|
||||
* offset, which occur on Windows for, and only for, desktop DC. This
|
||||
* occurs when you have multiple monitors, and at least one monitor
|
||||
* extends to the left, or above, the primaty monitor. The primary
|
||||
* monitor on Windows always start with offset (0,0), and any other points
|
||||
* to the left, or above, have negative offset. So the 'desktop DC' is
|
||||
* in fact a 'virtual desktop' which can start with extents in the negative
|
||||
* range.
|
||||
*
|
||||
* Why use new variables, and not the device transform? Simply because since
|
||||
* the device transform functions are exposed, a lot of 3rd party libraries
|
||||
* simply overwrite those, disregarding the prior content, instead of actually
|
||||
* adding the offset. GTK for example simply reset the device transform of the
|
||||
* desktop cairo surface to zero. So make some private member variables for
|
||||
* this, which will not be fiddled with externally.
|
||||
*/
|
||||
int x_ofs, y_ofs;
|
||||
} cairo_win32_surface_t;
|
||||
#define to_win32_surface(S) ((cairo_win32_surface_t *)(S))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue