Cairo and Juce, working together?

Hello,

I’m very interested in porting my project over to JUCE (since I just realized it does 80% of things I had planned on writing from scratch, and it does them very well). I already have some custom components written atop Cairo/Pango, in a Gtkmm custom widget. While the JUCE graphics toolkit is fast and complete, I would like to not rewrite my components (yet).

There seem to be numerous messages in the forums that allude to this being done, but I can’t find the API. From looking at the code, I can just create a custom Component to handle the UI input, but I’m not seeing where I can get access to the underlying GDI or D2D handle to give to the Cairo backend, without exposing it myself.

Is what I want to do supported at all?

Thanks,
Sean

Not really sure I understand what you have in mind… Juce just creates an X window for its backing, and draws everything onto that. You can get the WindowRef from the ComponentPeer class, but I’ve really no idea how you’d get it to talk to anything that uses Cairo…

Sorry for the obfuscation. It looks like ComponentPeer:getNativeHandle() with some #ifdef’d casting is going to be what I need. In short, I’d like to manipulate the X window/HWND/D2D device directly using Cairo (which supports the same back ends as JUCE). My plan is to develop a surrogate component that houses my custom controls. I’ll create my Cairo surface by initializing the backend (via getNativeHandle()), setting a Cairo clipping rectangle to the window coordinates of my custom component (and any intermediate transforms if it’s not window aligned) and draw when the Component is painted. Seems simple enough!

And thanks for your quick reply, Jules. I think you’ve got a really amazing project going here.

Sean

Your project is only for linux?

Linux, Windows, and Mac, although primary development is on Windows.

I can help create a window embedded x11 single you would have to draw on it using cairo.

ah, only for linux.

I was considering sharing the same xlib Window that JUCE uses (LinuxComponentPeer::windowH), and feeding it to cairo_xlib_surface_create() to create my cairo_surface_t. Do you suggest a different tactic?

Sean

I don’t really know anything about how Cairo works, but I guess that’d probably work, with a bit of hackery!

Now that juce has a flexible architecture for rendering support, it’d be nice one day to add a Cairo-based rendering engine for linux (and I guess for windows too).

add in juce_TopLevelWindow.h

line 32

void* CreaSubWin(Component* component,const int x, const int y, const int w, const int h);
void PosicionarSubWin (void* subwindow,int x, int y, int w, int h);

add in juce_linux_Windowing.cpp

line 3692

void* CreaSubWin(Component* component, const int x, const int y, const int w, const int h)
{

    jassert(component != 0);
    LinuxComponentPeer* const peer = dynamic_cast <LinuxComponentPeer*>(component->getTopLevelComponent()->getPeer());

    if(peer == 0)
        return NULL;

    XSync(display, False);

    Window windowH = (Window) peer->getNativeHandle();

    Window embeddedWindow = XCreateSimpleWindow(display, windowH,
                            x, y, w, h,
                            0, 0, 0);

    XSaveContext(display, (XID) embeddedWindow, improbableNumber, (XPointer) peer);

    XMapWindow(display, embeddedWindow);
    return (void*)embeddedWindow;
}

void PosicionarSubWin(void* ventana, int x, int y, int w, int h)
{
    XMoveResizeWindow(display, (Window)ventana,
                      x, y, jmax(1, w), jmax(1, h));
}

and remake library juce

sample

void* visor;
Component* viewsubWin;

visor = CreaSubWin(viewsubWin, viewsubWin->getX(),viewsubWin-> getY(), viewsubWin->getWidth(), viewsubWin->getHeight());

PosicionarSubWin(visor, viewsubWin->getX(), viewsubWin->getY() ,viewsubWin->getWidth(), viewsubWin->getHeight());



sample

void* visor;
Component* viewsubWin;

visor = CreaSubWin(viewsubWin, viewsubWin->getX(),viewsubWin-> getY(), viewsubWin->getWidth(), viewsubWin->getHeight());

PosicionarSubWin(visor, viewsubWin->getX(), viewsubWin->getY() ,viewsubWin->getWidth(), viewsubWin->getHeight());

visor is pointer of windows of X11

[quote=“yosvaniscc”]sample
visor is pointer of windows of X11[/quote]

Wow, it’s been a while since I looked at X11 code – thanks Yosvaniscc.

[quote=“jules”]I don’t really know anything about how Cairo works, but I guess that’d probably work, with a bit of hackery!
[/quote]

Indeed! I just had the thread the needle from the temporary backing image inside the software renderer to my Component, and everything renders just fine. Scary hack code that won’t work anywhere else below:

    juce::LowLevelGraphicsSoftwareRenderer* pJsw = MO_DYNAMIC_CAST(
        juce::LowLevelGraphicsSoftwareRenderer*,
        g.getInternalContext());
    if(pJsw)
    {
        juce::Image& img = pJsw->getImage();
        HDC hdc = (HDC)img.getSharedImage()->getNativePtr();
        if(hdc)
        {
            m_cairoSurface = Cairo::Win32Surface::create(hdc);
            m_drawCtx.rpCr = Cairo::Context::create(m_cairoSurface);
        }
    }

FYI: Cairo is a very capable cross-platform graphics framework that works under Windows, Mac and Linux. It effectively bridges its API more or less directly to the native OS frameworks, so you get a very good, almost native, performance.

It is definitely worth looking at:
http://cairographics.org/
http://cairographics.org/samples/

Andre