// Copyright 2013 Intel Corporation
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
//   list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/// @file
/// @brief Wrappers for GLX functions
///
/// Each wrapper catches any Xlib error emitted by the wrapped function. The
/// wrapper's signature matches the wrapped.
///
/// All Xlib error generated by Waffle must be caught by Waffle. Otherwise, the
/// Xlib error handler installed by the user will catch the error and may
/// handle it in a way Waffle doesn't like. Or, even worse, the default Xlib
/// error handler will catch it, which exits the process.

#pragma once

#include <stdbool.h>
#include <stdint.h>

#include <GL/glx.h>

#include "glx_platform.h"
#include "x11_wrappers.h"

static inline GLXFBConfig*
wrapped_glXChooseFBConfig(struct glx_platform *platform,
                          Display *dpy, int screen,
                          const int *attribList, int *nitems)
{
    X11_SAVE_ERROR_HANDLER
    GLXFBConfig *configs = platform->glXChooseFBConfig(dpy, screen,
                                                       attribList, nitems);
    X11_RESTORE_ERROR_HANDLER
    return configs;
}

static inline GLXContext
wrapped_glXCreateContextAttribsARB(struct glx_platform *platform,
                                   Display *dpy, GLXFBConfig config,
                                   GLXContext share_context, Bool direct,
                                   const int *attrib_list)
{
    X11_SAVE_ERROR_HANDLER
    GLXContext ctx = platform->glXCreateContextAttribsARB(
                        dpy, config, share_context, direct, attrib_list);
    X11_RESTORE_ERROR_HANDLER
    return ctx;
}

static inline GLXContext
wrapped_glXCreateNewContext(struct glx_platform *platform,
                            Display *dpy, GLXFBConfig config, int renderType,
                            GLXContext shareList, Bool direct)
{
    X11_SAVE_ERROR_HANDLER
    GLXContext ctx = platform->glXCreateNewContext(dpy, config, renderType,
                                                   shareList, direct);
    X11_RESTORE_ERROR_HANDLER
    return ctx;
}

static inline int
wrapped_glXGetFBConfigAttrib(struct glx_platform *platform,
                             Display *dpy, GLXFBConfig config,
                             int attribute, int *value)
{
    X11_SAVE_ERROR_HANDLER
    int error = platform->glXGetFBConfigAttrib(dpy, config, attribute, value);
    X11_RESTORE_ERROR_HANDLER
    return error;
}

static inline XVisualInfo*
wrapped_glXGetVisualFromFBConfig(struct glx_platform *platform,
                                 Display *dpy, GLXFBConfig config)
{
    X11_SAVE_ERROR_HANDLER
    XVisualInfo *vi = platform->glXGetVisualFromFBConfig(dpy, config);
    X11_RESTORE_ERROR_HANDLER
    return vi;
}

static inline void
wrapped_glXDestroyContext(struct glx_platform *platform,
                          Display *dpy, GLXContext ctx)
{
    X11_SAVE_ERROR_HANDLER
    platform->glXDestroyContext(dpy, ctx);
    X11_RESTORE_ERROR_HANDLER
}

static inline Bool
wrapped_glXMakeCurrent(struct glx_platform *platform,
                       Display *dpy, GLXDrawable drawable, GLXContext ctx)
{
    X11_SAVE_ERROR_HANDLER
    Bool ok = platform->glXMakeCurrent(dpy, drawable, ctx);
    X11_RESTORE_ERROR_HANDLER
    return ok;
}

static inline const char*
wrapped_glXQueryExtensionsString(struct glx_platform *platform,
                                 Display *dpy, int screen)
{
    X11_SAVE_ERROR_HANDLER
    const char *s = platform->glXQueryExtensionsString(dpy, screen);
    X11_RESTORE_ERROR_HANDLER
    return s;
}

static inline void
wrapped_glXSwapBuffers(struct glx_platform *platform,
                       Display *dpy, GLXDrawable drawable)
{
    X11_SAVE_ERROR_HANDLER
    platform->glXSwapBuffers(dpy, drawable);
    X11_RESTORE_ERROR_HANDLER
}
