I now started using cairo not only under X11 but also under Windows. My code is designed that way, that I only draw within the WM_PAINT event, creating a cairo surface using the HDC returned by BeginPaint (AFAIK this is the recommended way). For getting parts of the windows repainted because of changes (in reaction to user input) I call InvalidateRect (I also tried RedrawWindow with same results) with the RECT to get redrawn to trigger WM_PAINT message for the given region (AFAIK this is also the recommended way). This works fine for WM_PAINT messages created by the system (initial WM_PAINT on window open, WM_PAINT messages on window resize) but it fails for WM_PAINT messages created by InvalidateRect - if a valid RECT* is handed over. While the content of WM_PAINT is correct and cairo_clip_extents() on the temporary surface shows reasonable values in all cases (while having the coordinate origin obviously in lower left, instead upper left) , nothing gets drawn at all. As soon as I pass NULL as RECT*, redraw works like a charm. However doing full screen refresh on every redraw is obviously not a long term solution ;-) I assume that cases where the cliping reagion on the HDC is not the full window are differently (and possibly wrongly?) handled or I'm doing something wrong (e.g. are there any coordinate system transformations necessary on the Windows or cairo side I'm missing?). I'm using cairo-1.9.6 together with pixmap-0.18.2, the bug also occurs unde 1.9.8, but not under 1.8.10! For a demo compile below program and press a key in the window. It show do a InvalidRect for a part of the window, switch alternate to "true" and then draw in a different color over the fulkl window size. I you now see a red rectangle on a green background everything is fine, if you only see the initial green background, the second draw did nothing! I assume that something is wrong witht he handling of DC that have a cliping rectangle attached. If you change the InvalidRect rectangle to the full window size (0,0-256,256), everything works again. You can compile the application undermingw using the following command line: g++ cairo-gdi-demo.cpp `pkg-config.exe --cflags cairo ` `pkg-config.exe --libs cairo` -o cairo-gdi-demo.exe As you can see from the copyright, this is a modified exampl by Andrew Lim. /** cairo-gdi-demo.cpp Demonstrates how to get Cairo Graphics working with the Windows API and GDI. Author: Andrew Lim Email: danteshamest@gmail.com Site: windrealm.com */ #include <windows.h> #include <cmath> #include <cairo.h> #include <cairo-win32.h> #include <iostream> static bool alternative=false; /** Gradient demonstration. Taken from http://cairographics.org/samples/ */ void gradientExample( cairo_t* cr ) { if (!alternative) { cairo_set_source_rgb(cr,0,1,0); cairo_rectangle (cr, 0, 0, 256, 256); cairo_fill (cr); } else { cairo_set_source_rgb(cr,1,0,0); cairo_rectangle (cr, 0, 0, 256, 256); cairo_fill (cr); } } /** Changes the dimensions of a window's client area. */ void SetClientSize( HWND hwnd, int clientWidth, int clientHeight ) { if ( IsWindow( hwnd ) ) { DWORD dwStyle = GetWindowLongPtr( hwnd, GWL_STYLE ) ; DWORD dwExStyle = GetWindowLongPtr( hwnd, GWL_EXSTYLE ) ; HMENU menu = GetMenu( hwnd ) ; RECT rc = { 0, 0, clientWidth, clientHeight } ; AdjustWindowRectEx( &rc, dwStyle, menu ? TRUE : FALSE, dwExStyle ); SetWindowPos( hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOMOVE ) ; } } /** Handles WM_PAINT. */ LRESULT onPaint( HWND hwnd, WPARAM wParam, LPARAM lParam ) { PAINTSTRUCT ps ; HDC hdc = BeginPaint( hwnd, &ps ); // Create the cairo surface and context. cairo_surface_t *surface = cairo_win32_surface_create (hdc); cairo_t *cr = cairo_create (surface); // Draw on the cairo context. gradientExample( cr ); // Cleanup. cairo_destroy (cr); cairo_surface_destroy (surface); EndPaint( hwnd, &ps ); return 0 ; } LRESULT onKey( HWND hwnd, WPARAM wParam, LPARAM lParam ) { RECT rect; rect.left=128; rect.top=128; rect.right=64; rect.bottom=64; alternative=true; InvalidateRect(hwnd,&rect,false); } /** Handles WM_CLOSE. */ LRESULT onClose( HWND hwnd, WPARAM wParam, LPARAM lParam ) { PostQuitMessage( 0 ); return 0 ; } /** Handles our window's messages. */ LRESULT CALLBACK WndProc( HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam ) { switch(msg) { case WM_PAINT: return onPaint( hwnd, wParam, lParam ); case WM_CLOSE: return onClose( hwnd, wParam, lParam ); case WM_KEYDOWN: std::cout << "Key down!" << std::endl; return onKey( hwnd, wParam, lParam ); break; default: return DefWindowProc(hwnd,msg,wParam,lParam); } } int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrev, LPSTR args, int nShow ) { MSG msg ; WNDCLASS wc = {0}; wc.lpszClassName = TEXT( "CairoGdiWndClass" ); wc.hInstance = hInst ; wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wc.lpfnWndProc = WndProc ; wc.hCursor = LoadCursor(0,IDC_ARROW); RegisterClass(&wc); HWND hwnd = CreateWindow( wc.lpszClassName,TEXT("Cairo & GDI Demo"), WS_OVERLAPPEDWINDOW, 0,0,256,256,0,0,hInst,0); SetClientSize( hwnd, 256, 256 ); ShowWindow( hwnd, SW_SHOWNORMAL ); while( GetMessage(&msg,0,0,0) > 0 ) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }
Patch here http://sprunge.us/KOZU by Ingmar Runge ingmar@irsoft.de . There was a discussion on the mailing list but amazingly nobody cared to update this bug report with the information from the mailing list, I guessed the authors from that discussion would do that but they didn't. Someone with good knowledge about Cairo should review that patch and apply if it is correct or contact Ingmar to further discuss. Thanks a lot!!!
I tested on windows, it is fiexed.
Reopening since nothing was committed anywhere yet, there's just a patch attached here.
Created attachment 49554 [details] [review] Ingmar's patch This (i.e. Ingmar's) patch has been reviewed and deemed incomplete. Two possible solutions were suggested: - the simple way to fix the bug would be to make sure that the top-left corner of the surface are (0,0) - the best way to fix it would be to handle arbitrary extents for surfaces, which is presumably needed for handling unlimited surfaces (cairo has some support for them, but a lot of places still assume that surfaces are bounded and have (0,0) as top-left corner). FTR, I believe that https://bugs.freedesktop.org/show_bug.cgi?id=37140 might be related, or even the same bug.
Created attachment 49576 [details] Test case This is a self-contained cairo-style test case, which is fixed by Ingmar's patch.
The preferred solution seems to be implemented by: commit 91faf9c1cf79f44b48c0f14d2d551a68bf38b5a5 Author: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue Jul 26 15:50:32 2011 +0100 composite: Pass unbounded extents to initialisation For an unbounded surface we cannot assume (0, 0, surface_width, surface_height) as that is wrong and causes the operation to appear clipped. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> The cairo-gdi-demo.cpp now works as expected on cairo-master for me. Please reopen if you manage to reproduce the bug.
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.