From 39553be4dd02773a7d71eaab63efbf5c76f5e9d2 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 26 Jul 2019 22:49:30 +0200 Subject: Windows: Add Cairo support --- pugl/pugl_win.c | 15 ++++ pugl/pugl_win_cairo.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++ wscript | 10 ++- 3 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 pugl/pugl_win_cairo.c diff --git a/pugl/pugl_win.c b/pugl/pugl_win.c index 0f18eba..ac1993e 100644 --- a/pugl/pugl_win.c +++ b/pugl/pugl_win.c @@ -24,6 +24,9 @@ #ifdef PUGL_HAVE_GL #include "pugl/pugl_gl_backend.h" #endif +#ifdef PUGL_HAVE_CAIRO +#include "pugl/pugl_cairo_backend.h" +#endif #include #include @@ -93,6 +96,11 @@ puglCreateWindow(PuglView* view, const char* title) impl->backend = puglGlBackend(); #endif } + if (view->ctx_type == PUGL_CAIRO) { +#ifdef PUGL_HAVE_CAIRO + impl->backend = puglCairoBackend(); +#endif + } // Get refresh rate for resize draw timer DEVMODEA devMode = {0}; @@ -367,6 +375,7 @@ handleConfigure(PuglView* view, PuglEvent* event) event->configure.width = view->width; event->configure.height = view->height; + view->impl->backend->resize(view, view->width, view->height); return rect; } @@ -684,3 +693,9 @@ puglGetNativeWindow(PuglView* view) { return (PuglNativeWindow)view->impl->hwnd; } + +void* +puglGetContext(PuglView* view) +{ + return view->impl->backend->getContext(view); +} diff --git a/pugl/pugl_win_cairo.c b/pugl/pugl_win_cairo.c new file mode 100644 index 0000000..6dac736 --- /dev/null +++ b/pugl/pugl_win_cairo.c @@ -0,0 +1,200 @@ +/* + Copyright 2012-2019 David Robillard + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** + @file win_cairo.c Cairo graphics backend for Windows. +*/ + +#include "pugl/pugl_cairo_backend.h" +#include "pugl/pugl_internal_types.h" +#include "pugl/pugl_win.h" + +#include +#include + +#include + +typedef struct { + cairo_surface_t* surface; + cairo_t* cr; + HDC drawDc; + HBITMAP drawBitmap; +} PuglWinCairoSurface; + +static int +puglWinCairoCreateDrawContext(PuglView* view) +{ + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + + surface->drawDc = CreateCompatibleDC(impl->hdc); + surface->drawBitmap = CreateCompatibleBitmap( + impl->hdc, view->width, view->height); + + DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap)); + + cairo_status_t st = CAIRO_STATUS_SUCCESS; + if (!(surface->surface = cairo_win32_surface_create(surface->drawDc)) || + (st = cairo_surface_status(surface->surface)) || + !(surface->cr = cairo_create(surface->surface)) || + (st = cairo_status(surface->cr))) { + return PUGL_ERR_CREATE_CONTEXT; + } + + cairo_save(surface->cr); + return 0; +} + +static int +puglWinCairoDestroyDrawContext(PuglView* view) +{ + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + + DeleteDC(surface->drawDc); + DeleteObject(surface->drawBitmap); + cairo_destroy(surface->cr); + cairo_surface_destroy(surface->surface); + + surface->surface = NULL; + surface->cr = NULL; + surface->drawDc = NULL; + surface->drawBitmap = NULL; + + return 0; +} + +static int +puglWinCairoConfigure(PuglView* view) +{ + PuglInternals* const impl = view->impl; + PuglStatus st = PUGL_SUCCESS; + + if ((st = puglWinCreateWindow(view, "Pugl", &impl->hwnd, &impl->hdc))) { + return st; + } + + impl->pfd = puglWinGetPixelFormatDescriptor(&view->hints); + impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd); + + if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { + ReleaseDC(impl->hwnd, impl->hdc); + DestroyWindow(impl->hwnd); + impl->hwnd = NULL; + impl->hdc = NULL; + return PUGL_ERR_SET_FORMAT; + } + + impl->surface = (PuglWinCairoSurface*)calloc( + 1, sizeof(PuglWinCairoSurface)); + + return 0; +} + +static int +puglWinCairoCreate(PuglView* view) +{ + return puglWinCairoCreateDrawContext(view); +} + +static int +puglWinCairoDestroy(PuglView* view) +{ + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + + puglWinCairoDestroyDrawContext(view); + free(surface); + impl->surface = NULL; + + return 0; +} + +static int +puglWinCairoEnter(PuglView* view, bool drawing) +{ + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + if (!drawing) { + return 0; + } + + PAINTSTRUCT ps; + BeginPaint(view->impl->hwnd, &ps); + cairo_save(surface->cr); + + return 0; +} + +static int +puglWinCairoLeave(PuglView* view, bool drawing) +{ + PuglInternals* const impl = view->impl; + PuglWinCairoSurface* const surface = (PuglWinCairoSurface*)impl->surface; + if (!drawing) { + return 0; + } + + cairo_restore(surface->cr); + cairo_surface_flush(surface->surface); + BitBlt(impl->hdc, 0, 0, view->width, view->height, + surface->drawDc, 0, 0, SRCCOPY); + + PAINTSTRUCT ps; + EndPaint(view->impl->hwnd, &ps); + SwapBuffers(view->impl->hdc); + + return 0; +} + +static int +puglWinCairoResize(PuglView* view, + int width, + int height) +{ + view->width = width; + view->height = height; + int st = 0; + if ((st = puglWinCairoDestroyDrawContext(view)) || + (st = puglWinCairoCreateDrawContext(view))) { + fprintf(stderr, "ERR\n"); + return st; + } + + return 0; +} + +static void* +puglWinCairoGetContext(PuglView* view) +{ + return ((PuglWinCairoSurface*)view->impl->surface)->cr; +} + +const PuglBackend* +puglCairoBackend() +{ + static const PuglBackend backend = { + puglWinCairoConfigure, + puglWinCairoCreate, + puglWinCairoDestroy, + puglWinCairoEnter, + puglWinCairoLeave, + puglWinCairoResize, + puglWinCairoGetContext + }; + + return &backend; +} diff --git a/wscript b/wscript index 86c909d..bbaeff6 100644 --- a/wscript +++ b/wscript @@ -97,8 +97,14 @@ def build(bld): framework = [] libs = [] if bld.env.TARGET_PLATFORM == 'win32': - lib_source = ['pugl/pugl_win.c', 'pugl/pugl_win_gl.c'] - libs = ['opengl32', 'gdi32', 'user32'] + lib_source = ['pugl/pugl_win.c'] + libs = ['gdi32', 'user32'] + if bld.is_defined('HAVE_GL'): + lib_source += ['pugl/pugl_win_gl.c'] + libs += ['opengl32'] + if bld.is_defined('HAVE_CAIRO'): + lib_source += ['pugl/pugl_win_cairo.c'] + libs += ['cairo'] elif bld.env.TARGET_PLATFORM == 'darwin': lib_source = ['pugl/pugl_osx.m'] framework = ['Cocoa', 'OpenGL'] -- cgit v1.2.1