<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Compositor.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "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.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** 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
** OWNER 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."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "waylandeglintegration.h"

#include <QtCompositor/private/qwlcompositor_p.h>
#include <QtCompositor/private/qwlsurface_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLContext>
#include <qpa/qplatformscreen.h>
#include <QtGui/QWindow>
#include <QtCore/QPointer>

#include <QDebug>

#include <EGL/egl.h>
#include <EGL/eglext.h>

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#ifndef EGL_WL_bind_wayland_display
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
#endif

#ifndef EGL_KHR_image
typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
#endif

#ifndef GL_OES_EGL_image
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
#endif

QT_BEGIN_NAMESPACE

class WaylandEglIntegrationPrivate
{
public:
    WaylandEglIntegrationPrivate()
        : egl_display(EGL_NO_DISPLAY)
        , valid(false)
        , display_bound(false)
        , flipperConnected(false)
        , egl_bind_wayland_display(0)
        , egl_unbind_wayland_display(0)
        , egl_query_wayland_buffer(0)
        , egl_create_image(0)
        , egl_destroy_image(0)
        , gl_egl_image_target_texture_2d(0)
    { }
    EGLDisplay egl_display;
    bool valid;
    bool display_bound;
    bool flipperConnected;
    PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display;
    PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display;
    PFNEGLQUERYWAYLANDBUFFERWL egl_query_wayland_buffer;

    PFNEGLCREATEIMAGEKHRPROC egl_create_image;
    PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image;

    PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d;
};

WaylandEglIntegration::WaylandEglIntegration()
    : QWaylandGraphicsHardwareIntegration()
    , d_ptr(new WaylandEglIntegrationPrivate)
{
}

void WaylandEglIntegration::initializeHardware(QtWayland::Display *waylandDisplay)
{
    Q_D(WaylandEglIntegration);

    const bool ignoreBindDisplay = !qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty();

    QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
    if (!nativeInterface) {
        qWarning("Failed to initialize egl display. No native platform interface available.\n");
        return;
    }

    d->egl_display = nativeInterface->nativeResourceForWindow("EglDisplay", m_compositor->window());
    if (!d->egl_display) {
        qWarning("Failed to initialize egl display. Could not get EglDisplay for window.\n");
        return;
    }

    const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS);
    if ((!extensionString || !strstr(extensionString, "EGL_WL_bind_wayland_display")) && !ignoreBindDisplay) {
        qWarning("Failed to initialize egl display. There is no EGL_WL_bind_wayland_display extension.\n");
        return;
    }

    d->egl_bind_wayland_display = reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL"));
    d->egl_unbind_wayland_display = reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL"));
    if (!d->egl_bind_wayland_display || !d->egl_unbind_wayland_display && !ignoreBindDisplay) {
        qWarning("Failed to initialize egl display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.\n");
        return;
    }

    d->egl_query_wayland_buffer = reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL>(eglGetProcAddress("eglQueryWaylandBufferWL"));
    if (!d->egl_query_wayland_buffer) {
        qWarning("Failed to initialize egl display. Could not find eglQueryWaylandBufferWL.\n");
        return;
    }

    d->egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
    d->egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
    if (!d->egl_create_image || !d->egl_destroy_image) {
        qWarning("Failed to initialize egl display. Could not find eglCreateImageKHR and eglDestroyImageKHR.\n");
        return;
    }

    d->gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
    if (!d->gl_egl_image_target_texture_2d) {
        qWarning("Failed to initialize egl display. Could not find glEGLImageTargetTexture2DOES.\n");
        return;
    }

    if (d->egl_bind_wayland_display && d->egl_unbind_wayland_display) {
        d->display_bound = d->egl_bind_wayland_display(d->egl_display, waylandDisplay->handle());
        if (!d->display_bound || ignoreBindDisplay) {
            qWarning("Failed to initialize egl display. Could not bind Wayland display.\n");
            return;
        }
    }

    d->valid = true;

    qWarning("EGL Wayland extension successfully initialized.%s\n", !d->display_bound ? " eglBindWaylandDisplayWL ignored" : "");
}

GLuint WaylandEglIntegration::createTextureFromBuffer(struct ::wl_resource *buffer, QOpenGLContext *)
{
    Q_D(WaylandEglIntegration);
    if (!d->valid) {
        qWarning("createTextureFromBuffer() failed\n");
        return 0;
    }

    EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT,
                                          EGL_WAYLAND_BUFFER_WL,
                                          buffer, NULL);

    GLuint textureId;
    glGenTextures(1,&textureId);

    glBindTexture(GL_TEXTURE_2D, textureId);

    d->gl_egl_image_target_texture_2d(GL_TEXTURE_2D, image);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    d->egl_destroy_image(d->egl_display, image);

    return textureId;
}

bool WaylandEglIntegration::isYInverted(struct ::wl_resource *buffer) const
{
    Q_D(const WaylandEglIntegration);

#if defined(EGL_WAYLAND_Y_INVERTED_WL)
    EGLint isYInverted;
    EGLBoolean ret;
    ret = d->egl_query_wayland_buffer(d->egl_display, reinterpret_cast<struct ::wl_buffer *>(buffer), EGL_WAYLAND_Y_INVERTED_WL, &isYInverted);

    // Yes, this looks strange, but the specification says that EGL_FALSE return
    // value (not supported) should be treated the same as EGL_TRUE return value
    // and EGL_TRUE in value.
    if (ret == EGL_FALSE || isYInverted == EGL_TRUE)
        return true;
#endif

    return QWaylandGraphicsHardwareIntegration::isYInverted(buffer);
}

bool WaylandEglIntegration::setDirectRenderSurface(QWaylandSurface *surface)
{
    Q_D(WaylandEglIntegration);

    QPlatformScreen *screen = QPlatformScreen::platformScreenForWindow(m_compositor->window());
    QPlatformScreenPageFlipper *flipper = screen ? screen->pageFlipper() : 0;
    if (flipper && !d->flipperConnected) {
        QObject::connect(flipper, SIGNAL(bufferReleased(QPlatformScreenBuffer*)), m_compositor->handle(), SLOT(releaseBuffer(QPlatformScreenBuffer*)));
        d->flipperConnected = true;
    }
    Q_UNUSED(surface);
    return flipper;
}

void *WaylandEglIntegration::lockNativeBuffer(struct ::wl_resource *buffer, QOpenGLContext *) const
{
    Q_D(const WaylandEglIntegration);

    EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT,
                                          EGL_WAYLAND_BUFFER_WL,
                                          buffer, NULL);
    return image;
}

void WaylandEglIntegration::unlockNativeBuffer(void *native_buffer, QOpenGLContext *) const
{
    Q_D(const WaylandEglIntegration);
    EGLImageKHR image = static_cast<EGLImageKHR>(native_buffer);

    d->egl_destroy_image(d->egl_display, image);
}

QSize WaylandEglIntegration::bufferSize(struct ::wl_resource *buffer) const
{
    Q_D(const WaylandEglIntegration);

    int width, height;
    d->egl_query_wayland_buffer(d->egl_display, reinterpret_cast<struct ::wl_buffer *>(buffer), EGL_WIDTH, &width);
    d->egl_query_wayland_buffer(d->egl_display, reinterpret_cast<struct ::wl_buffer *>(buffer), EGL_HEIGHT, &height);

    return QSize(width, height);
}

QT_END_NAMESPACE
<commit_msg>Fix initialization without eglBindWaylandDisplayWL<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Compositor.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "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.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** 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
** OWNER 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."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "waylandeglintegration.h"

#include <QtCompositor/private/qwlcompositor_p.h>
#include <QtCompositor/private/qwlsurface_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLContext>
#include <qpa/qplatformscreen.h>
#include <QtGui/QWindow>
#include <QtCore/QPointer>

#include <QDebug>

#include <EGL/egl.h>
#include <EGL/eglext.h>

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#ifndef EGL_WL_bind_wayland_display
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
#endif

#ifndef EGL_KHR_image
typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
#endif

#ifndef GL_OES_EGL_image
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
#endif

QT_BEGIN_NAMESPACE

class WaylandEglIntegrationPrivate
{
public:
    WaylandEglIntegrationPrivate()
        : egl_display(EGL_NO_DISPLAY)
        , valid(false)
        , display_bound(false)
        , flipperConnected(false)
        , egl_bind_wayland_display(0)
        , egl_unbind_wayland_display(0)
        , egl_query_wayland_buffer(0)
        , egl_create_image(0)
        , egl_destroy_image(0)
        , gl_egl_image_target_texture_2d(0)
    { }
    EGLDisplay egl_display;
    bool valid;
    bool display_bound;
    bool flipperConnected;
    PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display;
    PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display;
    PFNEGLQUERYWAYLANDBUFFERWL egl_query_wayland_buffer;

    PFNEGLCREATEIMAGEKHRPROC egl_create_image;
    PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image;

    PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d;
};

WaylandEglIntegration::WaylandEglIntegration()
    : QWaylandGraphicsHardwareIntegration()
    , d_ptr(new WaylandEglIntegrationPrivate)
{
}

void WaylandEglIntegration::initializeHardware(QtWayland::Display *waylandDisplay)
{
    Q_D(WaylandEglIntegration);

    const bool ignoreBindDisplay = !qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty();

    QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
    if (!nativeInterface) {
        qWarning("Failed to initialize egl display. No native platform interface available.\n");
        return;
    }

    d->egl_display = nativeInterface->nativeResourceForWindow("EglDisplay", m_compositor->window());
    if (!d->egl_display) {
        qWarning("Failed to initialize egl display. Could not get EglDisplay for window.\n");
        return;
    }

    const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS);
    if ((!extensionString || !strstr(extensionString, "EGL_WL_bind_wayland_display")) && !ignoreBindDisplay) {
        qWarning("Failed to initialize egl display. There is no EGL_WL_bind_wayland_display extension.\n");
        return;
    }

    d->egl_bind_wayland_display = reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL"));
    d->egl_unbind_wayland_display = reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL"));
    if (!d->egl_bind_wayland_display || !d->egl_unbind_wayland_display && !ignoreBindDisplay) {
        qWarning("Failed to initialize egl display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.\n");
        return;
    }

    d->egl_query_wayland_buffer = reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL>(eglGetProcAddress("eglQueryWaylandBufferWL"));
    if (!d->egl_query_wayland_buffer) {
        qWarning("Failed to initialize egl display. Could not find eglQueryWaylandBufferWL.\n");
        return;
    }

    d->egl_create_image = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
    d->egl_destroy_image = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
    if (!d->egl_create_image || !d->egl_destroy_image) {
        qWarning("Failed to initialize egl display. Could not find eglCreateImageKHR and eglDestroyImageKHR.\n");
        return;
    }

    d->gl_egl_image_target_texture_2d = reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"));
    if (!d->gl_egl_image_target_texture_2d) {
        qWarning("Failed to initialize egl display. Could not find glEGLImageTargetTexture2DOES.\n");
        return;
    }

    if (d->egl_bind_wayland_display && d->egl_unbind_wayland_display) {
        d->display_bound = d->egl_bind_wayland_display(d->egl_display, waylandDisplay->handle());
        if (!d->display_bound && !ignoreBindDisplay) {
            qWarning("Failed to initialize egl display. Could not bind Wayland display.\n");
            return;
        }
    }

    d->valid = true;

    qWarning("EGL Wayland extension successfully initialized.%s\n", !d->display_bound ? " eglBindWaylandDisplayWL ignored" : "");
}

GLuint WaylandEglIntegration::createTextureFromBuffer(struct ::wl_resource *buffer, QOpenGLContext *)
{
    Q_D(WaylandEglIntegration);
    if (!d->valid) {
        qWarning("createTextureFromBuffer() failed\n");
        return 0;
    }

    EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT,
                                          EGL_WAYLAND_BUFFER_WL,
                                          buffer, NULL);

    GLuint textureId;
    glGenTextures(1,&textureId);

    glBindTexture(GL_TEXTURE_2D, textureId);

    d->gl_egl_image_target_texture_2d(GL_TEXTURE_2D, image);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    d->egl_destroy_image(d->egl_display, image);

    return textureId;
}

bool WaylandEglIntegration::isYInverted(struct ::wl_resource *buffer) const
{
    Q_D(const WaylandEglIntegration);

#if defined(EGL_WAYLAND_Y_INVERTED_WL)
    EGLint isYInverted;
    EGLBoolean ret;
    ret = d->egl_query_wayland_buffer(d->egl_display, reinterpret_cast<struct ::wl_buffer *>(buffer), EGL_WAYLAND_Y_INVERTED_WL, &isYInverted);

    // Yes, this looks strange, but the specification says that EGL_FALSE return
    // value (not supported) should be treated the same as EGL_TRUE return value
    // and EGL_TRUE in value.
    if (ret == EGL_FALSE || isYInverted == EGL_TRUE)
        return true;
#endif

    return QWaylandGraphicsHardwareIntegration::isYInverted(buffer);
}

bool WaylandEglIntegration::setDirectRenderSurface(QWaylandSurface *surface)
{
    Q_D(WaylandEglIntegration);

    QPlatformScreen *screen = QPlatformScreen::platformScreenForWindow(m_compositor->window());
    QPlatformScreenPageFlipper *flipper = screen ? screen->pageFlipper() : 0;
    if (flipper && !d->flipperConnected) {
        QObject::connect(flipper, SIGNAL(bufferReleased(QPlatformScreenBuffer*)), m_compositor->handle(), SLOT(releaseBuffer(QPlatformScreenBuffer*)));
        d->flipperConnected = true;
    }
    Q_UNUSED(surface);
    return flipper;
}

void *WaylandEglIntegration::lockNativeBuffer(struct ::wl_resource *buffer, QOpenGLContext *) const
{
    Q_D(const WaylandEglIntegration);

    EGLImageKHR image = d->egl_create_image(d->egl_display, EGL_NO_CONTEXT,
                                          EGL_WAYLAND_BUFFER_WL,
                                          buffer, NULL);
    return image;
}

void WaylandEglIntegration::unlockNativeBuffer(void *native_buffer, QOpenGLContext *) const
{
    Q_D(const WaylandEglIntegration);
    EGLImageKHR image = static_cast<EGLImageKHR>(native_buffer);

    d->egl_destroy_image(d->egl_display, image);
}

QSize WaylandEglIntegration::bufferSize(struct ::wl_resource *buffer) const
{
    Q_D(const WaylandEglIntegration);

    int width, height;
    d->egl_query_wayland_buffer(d->egl_display, reinterpret_cast<struct ::wl_buffer *>(buffer), EGL_WIDTH, &width);
    d->egl_query_wayland_buffer(d->egl_display, reinterpret_cast<struct ::wl_buffer *>(buffer), EGL_HEIGHT, &height);

    return QSize(width, height);
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>/*
 * HTTP server implementation.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "Internal.hxx"
#include "Request.hxx"
#include "direct.hxx"
#include "istream/istream_oo.hxx"

#include <daemon/log.h>

#include <sys/socket.h>
#include <errno.h>
#include <string.h>

size_t
HttpServerConnection::OnData(const void *data, size_t length)
{
    assert(socket.IsConnected() || request.request == nullptr);
    assert(response.istream.IsDefined());
    assert(!response.pending_drained);

    if (!socket.IsConnected())
        return 0;

    ssize_t nbytes = socket.Write(data, length);

    if (likely(nbytes >= 0)) {
        response.bytes_sent += nbytes;
        response.length += (off_t)nbytes;
        ScheduleWrite();
        return (size_t)nbytes;
    }

    if (gcc_likely(nbytes == WRITE_BLOCKING)) {
        response.want_write = true;
        return 0;
    }

    if (nbytes == WRITE_DESTROYED)
        return 0;

    ErrorErrno("write error on HTTP connection");
    return 0;
}

ssize_t
HttpServerConnection::OnDirect(FdType type, int fd, size_t max_length)
{
    assert(socket.IsConnected() || request.request == nullptr);
    assert(response.istream.IsDefined());
    assert(!response.pending_drained);

    if (!socket.IsConnected())
        return 0;

    ssize_t nbytes = socket.WriteFrom(fd, type, max_length);
    if (likely(nbytes > 0)) {
        response.bytes_sent += nbytes;
        response.length += (off_t)nbytes;
        ScheduleWrite();
    } else if (nbytes == WRITE_BLOCKING) {
        response.want_write = true;
        return ISTREAM_RESULT_BLOCKING;
    } else if (nbytes == WRITE_DESTROYED)
        return ISTREAM_RESULT_CLOSED;

    return nbytes;
}

void
HttpServerConnection::OnEof()
{
    assert(request.read_state != Request::START &&
           request.read_state != Request::HEADERS);
    assert(request.request != nullptr);
    assert(response.istream.IsDefined());
    assert(!response.pending_drained);

    response.istream.Clear();

    ResponseIstreamFinished();
}

void
HttpServerConnection::OnError(GError *error)
{
    assert(response.istream.IsDefined());

    response.istream.Clear();

    /* we clear this async_ref here so http_server_request_close()
       won't think we havn't sent a response yet */
    request.async_ref.Clear();

    g_prefix_error(&error, "error on HTTP response stream: ");
    Error(error);
}

void
HttpServerConnection::SetResponseIstream(Istream &r)
{
    response.istream.Set(r, *this, socket.GetDirectMask());
}

bool
HttpServerConnection::ResponseIstreamFinished()
{
    socket.UnscheduleWrite();

    Log();

    if (request.read_state == Request::BODY &&
        !request.expect_100_continue) {
        /* We are still reading the request body, which we don't need
           anymore.  To discard it, we simply close the connection by
           disabling keepalive; this seems cheaper than redirecting
           the rest of the body to /dev/null */
        keep_alive = false;
        request.read_state = Request::END;

        GError *error =
            g_error_new_literal(http_server_quark(), 0,
                                "request body discarded");
        request_body_reader->DestroyError(error);
        if (!IsValid())
            return false;
    }

    pool_trash(request.request->pool);
    pool_unref(request.request->pool);
    request.request = nullptr;
    request.bytes_received = 0;
    response.bytes_sent = 0;

    request.read_state = Request::START;

    if (keep_alive) {
        /* handle pipelined request (if any), or set up events for
           next request */

        socket.ScheduleReadNoTimeout(false);
        idle_timeout.Add(http_server_idle_timeout);

        return true;
    } else {
        /* keepalive disabled and response is finished: we must close
           the connection */

        if (socket.IsDrained()) {
            Done();
            return false;
        } else {
            /* there is still data in the filter's output buffer; wait for
               that to drain, which will trigger
               http_server_socket_drained() */
            assert(!response.pending_drained);

            response.pending_drained = true;

            return true;
        }
    }
}
<commit_msg>http_server: check for end of chunked request body again in ResponseIstreamFinished()<commit_after>/*
 * HTTP server implementation.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "Internal.hxx"
#include "Request.hxx"
#include "direct.hxx"
#include "istream/istream_oo.hxx"

#include <daemon/log.h>

#include <sys/socket.h>
#include <errno.h>
#include <string.h>

size_t
HttpServerConnection::OnData(const void *data, size_t length)
{
    assert(socket.IsConnected() || request.request == nullptr);
    assert(response.istream.IsDefined());
    assert(!response.pending_drained);

    if (!socket.IsConnected())
        return 0;

    ssize_t nbytes = socket.Write(data, length);

    if (likely(nbytes >= 0)) {
        response.bytes_sent += nbytes;
        response.length += (off_t)nbytes;
        ScheduleWrite();
        return (size_t)nbytes;
    }

    if (gcc_likely(nbytes == WRITE_BLOCKING)) {
        response.want_write = true;
        return 0;
    }

    if (nbytes == WRITE_DESTROYED)
        return 0;

    ErrorErrno("write error on HTTP connection");
    return 0;
}

ssize_t
HttpServerConnection::OnDirect(FdType type, int fd, size_t max_length)
{
    assert(socket.IsConnected() || request.request == nullptr);
    assert(response.istream.IsDefined());
    assert(!response.pending_drained);

    if (!socket.IsConnected())
        return 0;

    ssize_t nbytes = socket.WriteFrom(fd, type, max_length);
    if (likely(nbytes > 0)) {
        response.bytes_sent += nbytes;
        response.length += (off_t)nbytes;
        ScheduleWrite();
    } else if (nbytes == WRITE_BLOCKING) {
        response.want_write = true;
        return ISTREAM_RESULT_BLOCKING;
    } else if (nbytes == WRITE_DESTROYED)
        return ISTREAM_RESULT_CLOSED;

    return nbytes;
}

void
HttpServerConnection::OnEof()
{
    assert(request.read_state != Request::START &&
           request.read_state != Request::HEADERS);
    assert(request.request != nullptr);
    assert(response.istream.IsDefined());
    assert(!response.pending_drained);

    response.istream.Clear();

    ResponseIstreamFinished();
}

void
HttpServerConnection::OnError(GError *error)
{
    assert(response.istream.IsDefined());

    response.istream.Clear();

    /* we clear this async_ref here so http_server_request_close()
       won't think we havn't sent a response yet */
    request.async_ref.Clear();

    g_prefix_error(&error, "error on HTTP response stream: ");
    Error(error);
}

void
HttpServerConnection::SetResponseIstream(Istream &r)
{
    response.istream.Set(r, *this, socket.GetDirectMask());
}

bool
HttpServerConnection::ResponseIstreamFinished()
{
    socket.UnscheduleWrite();

    Log();

    /* check for end of chunked request body again, just in case
       DechunkIstream has announced this in a derred event */
    if (request.read_state == Request::BODY && request_body_reader->IsEOF()) {
        request.read_state = Request::END;
        request_body_reader->DestroyEof();
        if (!IsValid())
            return false;
    }

    if (request.read_state == Request::BODY &&
        !request.expect_100_continue) {
        /* We are still reading the request body, which we don't need
           anymore.  To discard it, we simply close the connection by
           disabling keepalive; this seems cheaper than redirecting
           the rest of the body to /dev/null */
        keep_alive = false;
        request.read_state = Request::END;

        GError *error =
            g_error_new_literal(http_server_quark(), 0,
                                "request body discarded");
        request_body_reader->DestroyError(error);
        if (!IsValid())
            return false;
    }

    pool_trash(request.request->pool);
    pool_unref(request.request->pool);
    request.request = nullptr;
    request.bytes_received = 0;
    response.bytes_sent = 0;

    request.read_state = Request::START;

    if (keep_alive) {
        /* handle pipelined request (if any), or set up events for
           next request */

        socket.ScheduleReadNoTimeout(false);
        idle_timeout.Add(http_server_idle_timeout);

        return true;
    } else {
        /* keepalive disabled and response is finished: we must close
           the connection */

        if (socket.IsDrained()) {
            Done();
            return false;
        } else {
            /* there is still data in the filter's output buffer; wait for
               that to drain, which will trigger
               http_server_socket_drained() */
            assert(!response.pending_drained);

            response.pending_drained = true;

            return true;
        }
    }
}
<|endoftext|>


<commit_before>#include "mainscene.h"
#include "../types.h"
#include <QGraphicsItem>
#include <QDebug>
#include <QGraphicsItemAnimation>
#include <QTimeLine>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QtGlobal>
#include <QFileInfo>

// Constructor & Destructor
MainScene::MainScene(qreal x, qreal y,
                      qreal width, qreal height,
                      QObject *parent)
 : QGraphicsScene(x,y,width,height,parent)
{
    this->window = dynamic_cast<MainWindow*>(parent);
    Q_CHECK_PTR(this->window);

    setupMain();
}

MainScene::~MainScene()
{
    delete background;
    delete start_button;
    delete credit_button;
    delete gplus_button;
    delete fb_button;
    delete all;
    delete copy;
    delete bgm_player;

    qDebug() << "Main Scene Destroyed";
}

// Methods
void MainScene::setupMain()
{
    // setup for main

    // set background
    background = new QGameItem(this, window);
    background->setImage(":images/main/main_background.png");
    background->setPos(0, 0);

    // set buttons
    start_button = new StartButton(this, window);
    start_button->setPos(535,470);

    credit_button = new CreditButton(this, window);
    credit_button->setPos(535,560);

    gplus_button = new QGameItem(this, window);
    gplus_button->setImage(":images/main/social_g+.png");
    gplus_button->setPos(1080, 610);

    fb_button = new QGameItem(this, window);
    fb_button->setImage(":images/main/social_fb.png");
    fb_button->setPos(1170, 610);

    all = new QGameItem(this, window);
    all->setImage(":images/main/all.png");
    all->setPos(1175, 5);

    copy = new QGameItem(this, window);
    copy->setImage(":images/main/copy.png");
    copy->setPos(350, 690);

    // setup BGM
    bgm_player = new QMediaPlayer();
    bgm_player->setMedia(QUrl::fromLocalFile(QFileInfo("sound/postech_marble_bgm.mp3").absoluteFilePath()));
}

void MainScene::animateMain()
{
    bgm_player->play();
}

// StartButton
StartButton::StartButton(QGraphicsScene *scene, MainWindow *window)
    : QGameItem(scene, window)
{
    // 버튼 초기 이미
    this->setImage(":/images/main/button_main_start.png");
}

StartButton::~StartButton()
{

}

void StartButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "Start button clicked.";
    setImage(":images/main/button_main_start_pressed.png");
}

void StartButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    setImage(":images/main/button_main_start.png");

    // move to ready scene
    window->switchScene(SceneType::READY);
}

void StartButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    // ignore input in this case
    setImage(":images/main/button_main_start.png");
}

// CreditButton
CreditButton::CreditButton(QGraphicsScene *scene, MainWindow *window)
    : QGameItem(scene, window)
{
    // 버튼 초기 이미지
    this->setImage(":/images/main/button_main_credit.png");
}

CreditButton::~CreditButton()
{

}

void CreditButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "Credit button clicked.";
    setImage(":images/main/button_main_credit_pressed.png");
}

void CreditButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    setImage(":images/main/button_main_credit.png");

    // move to ready scene
    window->switchScene(SceneType::CREDIT);
}

void CreditButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    // ignore input in this case
    setImage(":images/main/button_main_credit.png");
}
<commit_msg>MainScene: BGM repeat<commit_after>#include "mainscene.h"
#include "../types.h"
#include <QGraphicsItem>
#include <QDebug>
#include <QGraphicsItemAnimation>
#include <QTimeLine>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QtGlobal>
#include <QFileInfo>

// Constructor & Destructor
MainScene::MainScene(qreal x, qreal y,
                      qreal width, qreal height,
                      QObject *parent)
 : QGraphicsScene(x,y,width,height,parent)
{
    this->window = dynamic_cast<MainWindow*>(parent);
    Q_CHECK_PTR(this->window);

    setupMain();
    connect(bgm_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), bgm_player, SLOT(play()));
}

MainScene::~MainScene()
{
    delete background;
    delete start_button;
    delete credit_button;
    delete gplus_button;
    delete fb_button;
    delete all;
    delete copy;
    delete bgm_player;

    qDebug() << "Main Scene Destroyed";
}

// Methods
void MainScene::setupMain()
{
    // setup for main

    // set background
    background = new QGameItem(this, window);
    background->setImage(":images/main/main_background.png");
    background->setPos(0, 0);

    // set buttons
    start_button = new StartButton(this, window);
    start_button->setPos(535,470);

    credit_button = new CreditButton(this, window);
    credit_button->setPos(535,560);

    gplus_button = new QGameItem(this, window);
    gplus_button->setImage(":images/main/social_g+.png");
    gplus_button->setPos(1080, 610);

    fb_button = new QGameItem(this, window);
    fb_button->setImage(":images/main/social_fb.png");
    fb_button->setPos(1170, 610);

    all = new QGameItem(this, window);
    all->setImage(":images/main/all.png");
    all->setPos(1175, 5);

    copy = new QGameItem(this, window);
    copy->setImage(":images/main/copy.png");
    copy->setPos(350, 690);

    // setup BGM
    bgm_player = new QMediaPlayer();
    bgm_player->setMedia(QUrl::fromLocalFile(QFileInfo("sound/postech_marble_bgm.mp3").absoluteFilePath()));
}

void MainScene::animateMain()
{
    bgm_player->play();
}

// StartButton
StartButton::StartButton(QGraphicsScene *scene, MainWindow *window)
    : QGameItem(scene, window)
{
    // 버튼 초기 이미
    this->setImage(":/images/main/button_main_start.png");
}

StartButton::~StartButton()
{

}

void StartButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "Start button clicked.";
    setImage(":images/main/button_main_start_pressed.png");
}

void StartButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    setImage(":images/main/button_main_start.png");

    // move to ready scene
    window->switchScene(SceneType::READY);
}

void StartButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    // ignore input in this case
    setImage(":images/main/button_main_start.png");
}

// CreditButton
CreditButton::CreditButton(QGraphicsScene *scene, MainWindow *window)
    : QGameItem(scene, window)
{
    // 버튼 초기 이미지
    this->setImage(":/images/main/button_main_credit.png");
}

CreditButton::~CreditButton()
{

}

void CreditButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "Credit button clicked.";
    setImage(":images/main/button_main_credit_pressed.png");
}

void CreditButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    setImage(":images/main/button_main_credit.png");

    // move to ready scene
    window->switchScene(SceneType::CREDIT);
}

void CreditButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    // ignore input in this case
    setImage(":images/main/button_main_credit.png");
}
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2021                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

namespace openspace::luascriptfunctions {

int startRecording(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecording");

    using ghoul::lua::luaTypeToString;

    const std::string recordFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (recordFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }
    global::sessionRecording->setRecordDataFormat(
        interaction::SessionRecording::DataMode::Binary
    );
    global::sessionRecording->startRecording(recordFilePath);

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int startRecordingAscii(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecordingAscii");

    using ghoul::lua::luaTypeToString;

    const std::string recordFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (recordFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }
    global::sessionRecording->setRecordDataFormat(
        interaction::SessionRecording::DataMode::Ascii
    );
    global::sessionRecording->startRecording(recordFilePath);

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int stopRecording(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopRecording");

    global::sessionRecording->stopRecording();

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int startPlayback(lua_State* L, interaction::KeyframeTimeRef timeMode,
                  bool forceSimTimeAtStart)
{
    using ghoul::lua::luaTypeToString;
    const int nArguments = lua_gettop(L);
    bool loop = false;

    if (nArguments == 2) {
        loop = lua_toboolean(L, 2) == 1;
    }
    else if (nArguments != 1) {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 1 or 2, got %i",
            nArguments
        );
    }

    const std::string playbackFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (playbackFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }

    global::sessionRecording->startPlayback(
        const_cast<std::string&>(playbackFilePath),
        timeMode,
        forceSimTimeAtStart,
        loop
    );

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int startPlaybackDefault(lua_State* L) {
    using interaction::KeyframeNavigator;
    return startPlayback(L,
        interaction::KeyframeTimeRef::Relative_recordedStart, true);
}

int startPlaybackApplicationTime(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackApplicationTime");

    return startPlayback(L,
        interaction::KeyframeTimeRef::Relative_applicationStart, false);
}

int startPlaybackRecordedTime(lua_State* L) {
    using interaction::KeyframeNavigator;
    return startPlayback(L,
        interaction::KeyframeTimeRef::Relative_recordedStart, false);
}

int startPlaybackSimulationTime(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackSimulationTime");
    using interaction::KeyframeNavigator;
    return startPlayback(L,
        interaction::KeyframeTimeRef::Absolute_simTimeJ2000, false);
}

int stopPlayback(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPlayback");

    global::sessionRecording->stopPlayback();

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int enableTakeScreenShotDuringPlayback(lua_State* L) {
    const int nArguments = ghoul::lua::checkArgumentsAndThrow(
        L,
        { 0, 1 },
        "lua::enableTakeScreenShotDuringPlayback"
    );

    const int fps = nArguments == 0 ? 60 : ghoul::lua::value<int>(L, 1);

    global::sessionRecording->enableTakeScreenShotDuringPlayback(fps);

    lua_settop(L, 0);
    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int disableTakeScreenShotDuringPlayback(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableTakeScreenShotDuringPlayback");

    global::sessionRecording->disableTakeScreenShotDuringPlayback();

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int fileFormatConversion(lua_State* L) {
    using ghoul::lua::luaTypeToString;

    const std::string convertFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (convertFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }
    global::sessionRecording->convertFile(convertFilePath);

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int setPlaybackPause(lua_State* L) {
    const int nArguments = lua_gettop(L);

    if (nArguments == 1) {
        const bool pause = lua_toboolean(L, 1) == 1;
        global::sessionRecording->setPlaybackPause(pause);
    }
    else {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 1, got %i",
            nArguments
        );
    }

    lua_settop(L, 0);
    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int togglePlaybackPause(lua_State* L) {
    const int nArguments = lua_gettop(L);

    if (nArguments == 0) {
        bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused();
        global::sessionRecording->setPlaybackPause(!isPlaybackPaused);
    }
    else {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 0, got %i",
            nArguments
        );
    }

    lua_settop(L, 0);
    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int isPlayingBack(lua_State* L) {
    const int nArguments = lua_gettop(L);

    if (nArguments != 0) {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 0, got %i",
            nArguments
        );
    }

    ghoul::lua::push(L, global::sessionRecording->isPlayingBack());
    ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
    return 1;
}

} // namespace openspace::luascriptfunctions
<commit_msg>Restored a few asserts on lua commands<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2021                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

namespace openspace::luascriptfunctions {

int startRecording(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecording");

    using ghoul::lua::luaTypeToString;

    const std::string recordFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (recordFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }
    global::sessionRecording->setRecordDataFormat(
        interaction::SessionRecording::DataMode::Binary
    );
    global::sessionRecording->startRecording(recordFilePath);

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int startRecordingAscii(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecordingAscii");

    using ghoul::lua::luaTypeToString;

    const std::string recordFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (recordFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }
    global::sessionRecording->setRecordDataFormat(
        interaction::SessionRecording::DataMode::Ascii
    );
    global::sessionRecording->startRecording(recordFilePath);

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int stopRecording(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopRecording");

    global::sessionRecording->stopRecording();

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int startPlayback(lua_State* L, interaction::KeyframeTimeRef timeMode,
                  bool forceSimTimeAtStart)
{
    using ghoul::lua::luaTypeToString;
    const int nArguments = lua_gettop(L);
    bool loop = false;

    if (nArguments == 2) {
        loop = lua_toboolean(L, 2) == 1;
    }
    else if (nArguments != 1) {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 1 or 2, got %i",
            nArguments
        );
    }

    const std::string playbackFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (playbackFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }

    global::sessionRecording->startPlayback(
        const_cast<std::string&>(playbackFilePath),
        timeMode,
        forceSimTimeAtStart,
        loop
    );

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int startPlaybackDefault(lua_State* L) {
    using interaction::KeyframeNavigator;
    ghoul::lua::checkArgumentsAndThrow(L, {1, 2}, "lua::startPlaybackDefault");
    return startPlayback(L,
        interaction::KeyframeTimeRef::Relative_recordedStart, true);
}

int startPlaybackApplicationTime(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackApplicationTime");

    return startPlayback(L,
        interaction::KeyframeTimeRef::Relative_applicationStart, false);
}

int startPlaybackRecordedTime(lua_State* L) {
    using interaction::KeyframeNavigator;
    ghoul::lua::checkArgumentsAndThrow(L, {1, 2}, "lua::startPlaybackRecordedTime");
    return startPlayback(L,
        interaction::KeyframeTimeRef::Relative_recordedStart, false);
}

int startPlaybackSimulationTime(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackSimulationTime");
    using interaction::KeyframeNavigator;
    return startPlayback(L,
        interaction::KeyframeTimeRef::Absolute_simTimeJ2000, false);
}

int stopPlayback(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPlayback");

    global::sessionRecording->stopPlayback();

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int enableTakeScreenShotDuringPlayback(lua_State* L) {
    const int nArguments = ghoul::lua::checkArgumentsAndThrow(
        L,
        { 0, 1 },
        "lua::enableTakeScreenShotDuringPlayback"
    );

    const int fps = nArguments == 0 ? 60 : ghoul::lua::value<int>(L, 1);

    global::sessionRecording->enableTakeScreenShotDuringPlayback(fps);

    lua_settop(L, 0);
    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int disableTakeScreenShotDuringPlayback(lua_State* L) {
    ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableTakeScreenShotDuringPlayback");

    global::sessionRecording->disableTakeScreenShotDuringPlayback();

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int fileFormatConversion(lua_State* L) {
    using ghoul::lua::luaTypeToString;

    const std::string convertFilePath = ghoul::lua::value<std::string>(
        L,
        1,
        ghoul::lua::PopValue::Yes
    );

    if (convertFilePath.empty()) {
        return luaL_error(L, "filepath string is empty");
    }
    global::sessionRecording->convertFile(convertFilePath);

    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int setPlaybackPause(lua_State* L) {
    const int nArguments = lua_gettop(L);

    if (nArguments == 1) {
        const bool pause = lua_toboolean(L, 1) == 1;
        global::sessionRecording->setPlaybackPause(pause);
    }
    else {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 1, got %i",
            nArguments
        );
    }

    lua_settop(L, 0);
    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int togglePlaybackPause(lua_State* L) {
    const int nArguments = lua_gettop(L);

    if (nArguments == 0) {
        bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused();
        global::sessionRecording->setPlaybackPause(!isPlaybackPaused);
    }
    else {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 0, got %i",
            nArguments
        );
    }

    lua_settop(L, 0);
    ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
    return 0;
}

int isPlayingBack(lua_State* L) {
    const int nArguments = lua_gettop(L);

    if (nArguments != 0) {
        lua_settop(L, 0);
        return luaL_error(
            L,
            "bad number of arguments, expected 0, got %i",
            nArguments
        );
    }

    ghoul::lua::push(L, global::sessionRecording->isPlayingBack());
    ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack");
    return 1;
}

} // namespace openspace::luascriptfunctions
<|endoftext|>


<commit_before>#include "Console.hpp"

#include "logger.hpp"

#define PUTC(c) pc.putc(c)
#define GETC pc.getc
#define PRINTF(...) pc.printf(__VA_ARGS__)

const std::string Console::RX_BUFFER_FULL_MSG = "RX BUFFER FULL";
const std::string Console::COMMAND_BREAK_MSG = "*BREAK*\033[K";

shared_ptr<Console> Console::instance;

bool Console::iter_break_req = false;
bool Console::command_handled = true;
bool Console::command_ready = false;

Console::Console() : pc(USBTX, USBRX) {}

Console::~Console() { instance.reset(); }

shared_ptr<Console>& Console::Instance() {
    if (instance.get() == nullptr) instance.reset(new Console);

    return instance;
}

void Console::Init() {
    auto instance = Instance();

    // Set default values for the header parameters
    instance->CONSOLE_USER = "anon";
    instance->CONSOLE_HOSTNAME = "robot";
    instance->setHeader();

    // set baud rate, store the value before
    Baudrate(57600);

    // clear buffers
    instance->ClearRXBuffer();
    instance->ClearTXBuffer();

    // attach interrupt handlers
    // instance->pc.attach(&Console::RXCallback_MODSERIAL, MODSERIAL::RxIrq);
    // instance->pc.attach(&Console::TXCallback_MODSERIAL, MODSERIAL::TxIrq);
    instance->pc.attach(instance.get(), &Console::RXCallback, Serial::RxIrq);
    instance->pc.attach(instance.get(), &Console::TXCallback, Serial::TxIrq);

    // reset indicces
    instance->rxIndex = 0;
    instance->txIndex = 0;

    // Default for a host response escaped input terminating character
    // instance->SetEscEnd('R');

    LOG(INF3, "Hello from the 'common2015' library!");
}

void Console::PrintHeader() {
    // prints out a bash-like header
    Flush();
    instance->PRINTF("\r\n%s", instance->CONSOLE_HEADER.c_str());
    Flush();
}

void Console::ClearRXBuffer() { memset(rxBuffer, '\0', BUFFER_LENGTH); }

void Console::ClearTXBuffer() { memset(txBuffer, '\0', BUFFER_LENGTH); }

void Console::Flush() { fflush(stdout); }

void Console::RXCallback() {
    // If for some reason more than one character is in the buffer when the
    // interrupt is called, handle them all.
    while (pc.readable()) {
        // If there is an command that hasn't finished yet, ignore the character
        // for now
        if (command_handled == false && command_ready == true) {
            return;

        } else {
            // Otherwise, continue as normal
            // read the char that caused the interrupt
            char c = GETC();

            // if the buffer is full, ignore the chracter and print a
            // warning to the console
            if (rxIndex >= (BUFFER_LENGTH - 5) && c != BACKSPACE_FLAG_CHAR) {
                rxIndex = 0;
                PRINTF("%s\r\n", RX_BUFFER_FULL_MSG.c_str());
                Flush();

                // Execute the function that sets up the console after a
                // command's execution.
                // This will ensure everything flushes corectly on a full buffer
                CommandHandled(true);
            }

            // if a new line character is sent, process the current buffer
            else if (c == NEW_LINE_CHAR) {
                // print new line prior to executing
                PRINTF("%c\n", NEW_LINE_CHAR);
                Flush();
                rxBuffer[rxIndex] = '\0';

                command_ready = true;
                command_handled = false;
            }

            // if a backspace is requested, handle it.
            else if (c == BACKSPACE_FLAG_CHAR)
                if (rxIndex > 0) {  // instance->CONSOLE_HEADER.length()) {
                    // re-terminate the string
                    rxBuffer[--rxIndex] = '\0';

                    // 1) Move cursor back
                    // 2) Write a space to clear the character
                    // 3) Move back cursor again
                    PUTC(BACKSPACE_REPLY_CHAR);
                    PUTC(BACKSPACE_REPLACE_CHAR);
                    PUTC(BACKSPACE_REPLY_CHAR);
                    Flush();
                } else {
                    /* do nothing if we can't back space any more */
                }

            // set that a command break was requested flag if we received a
            // break character
            else if (c == BREAK_CHAR) {
                iter_break_req = true;
            }

            // No special character, add it to the buffer and return it to
            // the terminal to be visible.
            else {
                if (!(c == ARROW_UP_KEY || c == ARROW_DOWN_KEY ||
                      c == ARROW_DOWN_KEY || c == ARROW_DOWN_KEY)) {
                    rxBuffer[rxIndex++] = c;
                }
                PUTC(c);
                Flush();
            }
        }
    }
}

void Console::TXCallback() {
    NVIC_DisableIRQ(UART0_IRQn);
    // handle transmission interrupts if necessary here
    NVIC_EnableIRQ(UART0_IRQn);
}

void Console::RequestSystemStop() { Instance()->sysStopReq = true; }

bool Console::IsSystemStopRequested() { return Instance()->sysStopReq; }

bool Console::IterCmdBreakReq() { return iter_break_req; }

void Console::IterCmdBreakReq(bool newState) {
    iter_break_req = newState;

    // Print out the header if an iterating command is stopped
    if (newState == false) {
        instance->PRINTF("%s", COMMAND_BREAK_MSG.c_str());
        PrintHeader();
    }
}

char* Console::rxBufferPtr() { return instance->rxBuffer; }

bool Console::CommandReady() { return command_ready; }

void Console::CommandHandled(bool cmdDoneState) {
    // update the class's flag for if a command was handled or not
    command_handled = cmdDoneState;

    // Clean up after command execution
    instance->rxIndex = 0;

    // reset our outgoing flag saying if there's a valid command sequence in the
    // RX buffer or now
    command_ready = false;

    // print out the header without a newline first
    if (iter_break_req == false) {
        instance->PRINTF("%s", instance->CONSOLE_HEADER.c_str());
        Flush();
    }
}

void Console::changeHostname(const std::string& hostname) {
    instance->CONSOLE_HOSTNAME = hostname;
    instance->setHeader();
}

void Console::changeUser(const std::string& user) {
    instance->CONSOLE_USER = user;
    instance->setHeader();
}

void Console::setHeader() {
    instance->CONSOLE_HEADER =
        "\033[1;36m" + instance->CONSOLE_USER + "\033[1;32m@\033[01;33m" +
        instance->CONSOLE_HOSTNAME + " \033[36m$\033[0m \033[0J\033[0m";
    // instance->CONSOLE_HEADER = instance->CONSOLE_USER + "@" +
    // instance->CONSOLE_HOSTNAME + " $ ";
}

void Console::Baudrate(uint16_t baud) {
    instance->baudrate = baud;
    instance->pc.baud(instance->baudrate);
}

uint16_t Console::Baudrate() { return instance->baudrate; }

void Console::RXCallback_MODSERIAL(MODSERIAL_IRQ_INFO* info) {
    Console::RXCallback();
}

void Console::TXCallback_MODSERIAL(MODSERIAL_IRQ_INFO* info) {
    Console::TXCallback();
}

void Console::SetEscEnd(char c) { instance->esc_host_end_char = c; }

std::string Console::GetHostResponse() {
    if (instance->esc_host_res_rdy == true) {
        instance->esc_host_res_rdy = false;

        return instance->esc_host_res;
    } else {
        return "";
    }
}

void Console::ShowLogo() {
    Flush();

    instance->PRINTF(
        "\033[01;33m"
        "   _____       _                _            _        _\r\n"
        "  |  __ \\     | |              | |          | |      | |      \r\n"
        "  | |__) |___ | |__   ___      | | __ _  ___| | _____| |_ ___ \r\n"
        "  |  _  // _ \\| '_ \\ / _ \\ _   | |/ _` |/ __| |/ / _ \\ __/ __|\r\n"
        "  | | \\ \\ (_) | |_) | (_) | |__| | (_| | (__|   <  __/ |_\\__ \\\r\n"
        "  |_|  \\_\\___/|_.__/ \\___/ \\____/ "
        "\\__,_|\\___|_|\\_\\___|\\__|___/\r\n\033[0m");

    Flush();
}

void Console::SetTitle(const std::string& title) {
    instance->PRINTF("\033]0;%s\007", title.c_str());
    Flush();
}
<commit_msg>stopping interrupt changes on tx callback<commit_after>#include "Console.hpp"

#include "logger.hpp"

#define PUTC(c) pc.putc(c)
#define GETC pc.getc
#define PRINTF(...) pc.printf(__VA_ARGS__)

const std::string Console::RX_BUFFER_FULL_MSG = "RX BUFFER FULL";
const std::string Console::COMMAND_BREAK_MSG = "*BREAK*\033[K";

shared_ptr<Console> Console::instance;

bool Console::iter_break_req = false;
bool Console::command_handled = true;
bool Console::command_ready = false;

Console::Console() : pc(USBTX, USBRX) {}

Console::~Console() { instance.reset(); }

shared_ptr<Console>& Console::Instance() {
    if (instance.get() == nullptr) instance.reset(new Console);

    return instance;
}

void Console::Init() {
    auto instance = Instance();

    // Set default values for the header parameters
    instance->CONSOLE_USER = "anon";
    instance->CONSOLE_HOSTNAME = "robot";
    instance->setHeader();

    // set baud rate, store the value before
    Baudrate(57600);

    // clear buffers
    instance->ClearRXBuffer();
    instance->ClearTXBuffer();

    // attach interrupt handlers
    // instance->pc.attach(&Console::RXCallback_MODSERIAL, MODSERIAL::RxIrq);
    // instance->pc.attach(&Console::TXCallback_MODSERIAL, MODSERIAL::TxIrq);
    instance->pc.attach(instance.get(), &Console::RXCallback, Serial::RxIrq);
    instance->pc.attach(instance.get(), &Console::TXCallback, Serial::TxIrq);

    // reset indicces
    instance->rxIndex = 0;
    instance->txIndex = 0;

    // Default for a host response escaped input terminating character
    // instance->SetEscEnd('R');

    LOG(INF3, "Hello from the 'common2015' library!");
}

void Console::PrintHeader() {
    // prints out a bash-like header
    Flush();
    instance->PRINTF("\r\n%s", instance->CONSOLE_HEADER.c_str());
    Flush();
}

void Console::ClearRXBuffer() { memset(rxBuffer, '\0', BUFFER_LENGTH); }

void Console::ClearTXBuffer() { memset(txBuffer, '\0', BUFFER_LENGTH); }

void Console::Flush() { fflush(stdout); }

void Console::RXCallback() {
    // If for some reason more than one character is in the buffer when the
    // interrupt is called, handle them all.
    while (pc.readable()) {
        // If there is an command that hasn't finished yet, ignore the character
        // for now
        if (command_handled == false && command_ready == true) {
            return;

        } else {
            // Otherwise, continue as normal
            // read the char that caused the interrupt
            char c = GETC();

            // if the buffer is full, ignore the chracter and print a
            // warning to the console
            if (rxIndex >= (BUFFER_LENGTH - 5) && c != BACKSPACE_FLAG_CHAR) {
                rxIndex = 0;
                PRINTF("%s\r\n", RX_BUFFER_FULL_MSG.c_str());
                Flush();

                // Execute the function that sets up the console after a
                // command's execution.
                // This will ensure everything flushes corectly on a full buffer
                CommandHandled(true);
            }

            // if a new line character is sent, process the current buffer
            else if (c == NEW_LINE_CHAR) {
                // print new line prior to executing
                PRINTF("%c\n", NEW_LINE_CHAR);
                Flush();
                rxBuffer[rxIndex] = '\0';

                command_ready = true;
                command_handled = false;
            }

            // if a backspace is requested, handle it.
            else if (c == BACKSPACE_FLAG_CHAR)
                if (rxIndex > 0) {  // instance->CONSOLE_HEADER.length()) {
                    // re-terminate the string
                    rxBuffer[--rxIndex] = '\0';

                    // 1) Move cursor back
                    // 2) Write a space to clear the character
                    // 3) Move back cursor again
                    PUTC(BACKSPACE_REPLY_CHAR);
                    PUTC(BACKSPACE_REPLACE_CHAR);
                    PUTC(BACKSPACE_REPLY_CHAR);
                    Flush();
                } else {
                    /* do nothing if we can't back space any more */
                }

            // set that a command break was requested flag if we received a
            // break character
            else if (c == BREAK_CHAR) {
                iter_break_req = true;
            }

            // No special character, add it to the buffer and return it to
            // the terminal to be visible.
            else {
                if (!(c == ARROW_UP_KEY || c == ARROW_DOWN_KEY ||
                      c == ARROW_DOWN_KEY || c == ARROW_DOWN_KEY)) {
                    rxBuffer[rxIndex++] = c;
                }
                PUTC(c);
                Flush();
            }
        }
    }
}

void Console::TXCallback() {
    // NVIC_DisableIRQ(UART0_IRQn);
    // handle transmission interrupts if necessary here
    // NVIC_EnableIRQ(UART0_IRQn);
}

void Console::RequestSystemStop() { Instance()->sysStopReq = true; }

bool Console::IsSystemStopRequested() { return Instance()->sysStopReq; }

bool Console::IterCmdBreakReq() { return iter_break_req; }

void Console::IterCmdBreakReq(bool newState) {
    iter_break_req = newState;

    // Print out the header if an iterating command is stopped
    if (newState == false) {
        instance->PRINTF("%s", COMMAND_BREAK_MSG.c_str());
        PrintHeader();
    }
}

char* Console::rxBufferPtr() { return instance->rxBuffer; }

bool Console::CommandReady() { return command_ready; }

void Console::CommandHandled(bool cmdDoneState) {
    // update the class's flag for if a command was handled or not
    command_handled = cmdDoneState;

    // Clean up after command execution
    instance->rxIndex = 0;

    // reset our outgoing flag saying if there's a valid command sequence in the
    // RX buffer or now
    command_ready = false;

    // print out the header without a newline first
    if (iter_break_req == false) {
        instance->PRINTF("%s", instance->CONSOLE_HEADER.c_str());
        Flush();
    }
}

void Console::changeHostname(const std::string& hostname) {
    instance->CONSOLE_HOSTNAME = hostname;
    instance->setHeader();
}

void Console::changeUser(const std::string& user) {
    instance->CONSOLE_USER = user;
    instance->setHeader();
}

void Console::setHeader() {
    instance->CONSOLE_HEADER =
        "\033[1;36m" + instance->CONSOLE_USER + "\033[1;32m@\033[01;33m" +
        instance->CONSOLE_HOSTNAME + " \033[36m$\033[0m \033[0J\033[0m";
    // instance->CONSOLE_HEADER = instance->CONSOLE_USER + "@" +
    // instance->CONSOLE_HOSTNAME + " $ ";
}

void Console::Baudrate(uint16_t baud) {
    instance->baudrate = baud;
    instance->pc.baud(instance->baudrate);
}

uint16_t Console::Baudrate() { return instance->baudrate; }

void Console::RXCallback_MODSERIAL(MODSERIAL_IRQ_INFO* info) {
    Console::RXCallback();
}

void Console::TXCallback_MODSERIAL(MODSERIAL_IRQ_INFO* info) {
    Console::TXCallback();
}

void Console::SetEscEnd(char c) { instance->esc_host_end_char = c; }

std::string Console::GetHostResponse() {
    if (instance->esc_host_res_rdy == true) {
        instance->esc_host_res_rdy = false;

        return instance->esc_host_res;
    } else {
        return "";
    }
}

void Console::ShowLogo() {
    Flush();

    instance->PRINTF(
        "\033[01;33m"
        "   _____       _                _            _        _\r\n"
        "  |  __ \\     | |              | |          | |      | |      \r\n"
        "  | |__) |___ | |__   ___      | | __ _  ___| | _____| |_ ___ \r\n"
        "  |  _  // _ \\| '_ \\ / _ \\ _   | |/ _` |/ __| |/ / _ \\ __/ __|\r\n"
        "  | | \\ \\ (_) | |_) | (_) | |__| | (_| | (__|   <  __/ |_\\__ \\\r\n"
        "  |_|  \\_\\___/|_.__/ \\___/ \\____/ "
        "\\__,_|\\___|_|\\_\\___|\\__|___/\r\n\033[0m");

    Flush();
}

void Console::SetTitle(const std::string& title) {
    instance->PRINTF("\033]0;%s\007", title.c_str());
    Flush();
}
<|endoftext|>


<commit_before>#include "GameLogger.h"

GameLogger::GameLogger()
{
  logfileManager.openFile("/home/nao/game.log");
}

void GameLogger::execute()
{
  std::stringstream& stream =
      logfileManager.log(getFrameInfo().getFrameNumber(), "BehaviorStatus");
  Serializer<BehaviorStatus>::serialize(getBehaviorStatus(), stream);
}

GameLogger::~GameLogger()
{
  logfileManager.closeFile();
}
<commit_msg>always log the full ringbuffer<commit_after>#include "GameLogger.h"

GameLogger::GameLogger()
  : logfileManager(true)
{
  logfileManager.openFile("/home/nao/game.log");
}

void GameLogger::execute()
{
  std::stringstream& stream =
      logfileManager.log(getFrameInfo().getFrameNumber(), "BehaviorStatus");
  Serializer<BehaviorStatus>::serialize(getBehaviorStatus(), stream);
}

GameLogger::~GameLogger()
{
  logfileManager.closeFile();
}
<|endoftext|>


<commit_before>#include "coreapplication.h"
#include "debug.h"
#include "utils.h"
#include "widgets/setupdialog.h"

#include <QDialog>
#include <QFontDatabase>
#include <QMessageBox>

CoreApplication::CoreApplication(int &argc, char **argv)
    : QApplication(argc, argv),
      _mainWindow(NULL),
      _notification(),
      _jobsOption(false)
{
    qRegisterMetaType<TaskStatus>("TaskStatus");
    qRegisterMetaType<QList<QUrl>>("QList<QUrl>");
    qRegisterMetaType<BackupTaskPtr>("BackupTaskPtr");
    qRegisterMetaType<QList<ArchivePtr>>("QList<ArchivePtr >");
    qRegisterMetaType<ArchivePtr>("ArchivePtr");
    qRegisterMetaType<ArchiveRestoreOptions>("ArchiveRestoreOptions");
    qRegisterMetaType<QSqlQuery>("QSqlQuery");
    qRegisterMetaType<JobPtr>("JobPtr");
    qRegisterMetaType<QMap<QString, JobPtr>>("QMap<QString, JobPtr>");
    qRegisterMetaType<QSystemTrayIcon::ActivationReason>("QSystemTrayIcon::ActivationReason");
    qRegisterMetaType<TarsnapError>("TarsnapError");

    QCoreApplication::setOrganizationName(QLatin1String("Tarsnap Backup Inc."));
    QCoreApplication::setOrganizationDomain(QLatin1String("tarsnap.com"));
    QCoreApplication::setApplicationName(QLatin1String("Tarsnap"));
    QCoreApplication::setApplicationVersion(APP_VERSION);
}

CoreApplication::~CoreApplication()
{
    if(_mainWindow)
        delete _mainWindow;
}

void CoreApplication::parseArgs()
{
    QCommandLineParser parser;
    parser.setApplicationDescription(QLatin1String("Tarsnap GUI - Online backups for the truly lazy"));
    parser.addHelpOption();
    parser.addVersionOption();
    QCommandLineOption jobsOption(QStringList() << "j" << "jobs",
                                  tr("Executes all jobs sequentially that have the \'Include in scheduled backups\' option checked."
                                     " The application runs headless and useful information is printed to standard out and error."));
    QCommandLineOption appDataOption(QStringList() << "a" << "appdata",
                                    tr("Use the specified app data directory."
                                       " Useful for multiple configurations on the same machine (INI format is implied)."),
                                    tr("directory"));
    parser.addOption(jobsOption);
    parser.addOption(appDataOption);
    parser.process(arguments());
    _jobsOption = parser.isSet(jobsOption);
    _appDataDir = parser.value(appDataOption);
}

bool CoreApplication::initialize()
{
    parseArgs();

    QSettings settings;

    if(!_appDataDir.isEmpty())
    {
        settings.setPath(QSettings::IniFormat, QSettings::UserScope, _appDataDir);
        settings.setDefaultFormat(QSettings::IniFormat);
    }

    bool wizardDone = settings.value("app/wizard_done", false).toBool();
    if(!wizardDone)
    {
        // Show the first time setup dialog
        SetupDialog wizard;
        connect(&wizard, &SetupDialog::getTarsnapVersion, &_taskManager,
                &TaskManager::getTarsnapVersion);
        connect(&_taskManager, &TaskManager::tarsnapVersion, &wizard,
                &SetupDialog::setTarsnapVersion);
        connect(&wizard, &SetupDialog::requestRegisterMachine, &_taskManager,
                &TaskManager::registerMachine);
        connect(&_taskManager, &TaskManager::registerMachineStatus, &wizard,
                &SetupDialog::registerMachineStatus);
        connect(&_taskManager, &TaskManager::idle, &wizard,
                &SetupDialog::updateLoadingAnimation);

        if(QDialog::Rejected == wizard.exec())
        {
            quit();       // if we're running in the loop
            return false; // if called from main
        }
    }

    bool iniFormat = settings.value("app/ini_format", false).toBool();
    if(iniFormat)
    {
        QString appData = settings.value("app/app_data", APPDATA).toString();
        settings.setPath(QSettings::IniFormat, QSettings::UserScope, appData);
        settings.setDefaultFormat(QSettings::IniFormat);
    }

    connect(&_taskManager, &TaskManager::displayNotification,
            &_notification, &Notification::displayNotification, QUEUED);
    QMetaObject::invokeMethod(&_taskManager, "loadSettings", QUEUED);
    QMetaObject::invokeMethod(&_journal, "load", QUEUED);

    if(_jobsOption)
    {
        connect(&_notification, &Notification::activated, this,
                &CoreApplication::showMainWindow, QUEUED);
        connect(&_notification, &Notification::messageClicked, this,
                &CoreApplication::showMainWindow, QUEUED);
        _taskManager.setHeadless(true);
        QMetaObject::invokeMethod(&_taskManager, "runScheduledJobs", QUEUED);
    }
    else
    {
        showMainWindow();
    }

    return true;
}

void CoreApplication::showMainWindow()
{
    if(_mainWindow != NULL)
        return;

    _taskManager.setHeadless(false);
    disconnect(&_notification, &Notification::activated, this,
               &CoreApplication::showMainWindow);
    disconnect(&_notification, &Notification::messageClicked, this,
               &CoreApplication::showMainWindow);

    _mainWindow = new MainWindow();
    Q_ASSERT(_mainWindow != NULL);

    connect(_mainWindow, &MainWindow::getTarsnapVersion, &_taskManager,
            &TaskManager::getTarsnapVersion, QUEUED);
    connect(&_taskManager, &TaskManager::tarsnapVersion, _mainWindow,
            &MainWindow::setTarsnapVersion, QUEUED);
    connect(_mainWindow, &MainWindow::backupNow, &_taskManager,
            &TaskManager::backupNow, QUEUED);
    connect(_mainWindow, &MainWindow::loadArchives, &_taskManager,
            &TaskManager::loadArchives, QUEUED);
    connect(&_taskManager, &TaskManager::archiveList, _mainWindow,
            &MainWindow::archiveList, QUEUED);
    connect(_mainWindow, &MainWindow::deleteArchives, &_taskManager,
            &TaskManager::deleteArchives, QUEUED);
    connect(_mainWindow, &MainWindow::loadArchiveStats, &_taskManager,
            &TaskManager::getArchiveStats, QUEUED);
    connect(_mainWindow, &MainWindow::loadArchiveContents, &_taskManager,
            &TaskManager::getArchiveContents, QUEUED);
    connect(&_taskManager, &TaskManager::idle, _mainWindow,
            &MainWindow::updateLoadingAnimation, QUEUED);
    connect(_mainWindow, &MainWindow::getOverallStats, &_taskManager,
            &TaskManager::getOverallStats, QUEUED);
    connect(&_taskManager, &TaskManager::overallStats, _mainWindow,
            &MainWindow::updateSettingsSummary, QUEUED);
    connect(_mainWindow, &MainWindow::repairCache, &_taskManager,
            &TaskManager::fsck, QUEUED);
    connect(_mainWindow, &MainWindow::settingsChanged, &_taskManager,
            &TaskManager::loadSettings, QUEUED);
    connect(_mainWindow, &MainWindow::purgeArchives, &_taskManager,
            &TaskManager::nuke, QUEUED);
    connect(_mainWindow, &MainWindow::restoreArchive, &_taskManager,
            &TaskManager::restoreArchive, QUEUED);
    connect(_mainWindow, &MainWindow::runSetupWizard, this,
            &CoreApplication::reinit, QUEUED);
    connect(_mainWindow, &MainWindow::stopTasks, &_taskManager,
            &TaskManager::stopTasks, QUEUED);
    connect(_mainWindow, &MainWindow::loadJobs, &_taskManager,
            &TaskManager::loadJobs, QUEUED);
    connect(&_taskManager, &TaskManager::jobsList, _mainWindow,
            &MainWindow::jobsList, QUEUED);
    connect(_mainWindow, &MainWindow::deleteJob, &_taskManager,
            &TaskManager::deleteJob, QUEUED);
    connect(_mainWindow, &MainWindow::getTaskInfo, &_taskManager,
            &TaskManager::getTaskInfo, QUEUED);
    connect(&_taskManager, &TaskManager::taskInfo, _mainWindow,
            &MainWindow::displayStopTasks, QUEUED);
    connect(_mainWindow, &MainWindow::jobAdded, &_taskManager,
            &TaskManager::addJob, QUEUED);
    connect(&_taskManager, &TaskManager::message, _mainWindow,
            &MainWindow::updateStatusMessage, QUEUED);
    connect(&_taskManager, &TaskManager::message, &_journal, &Journal::log,
            QUEUED);
    connect(&_taskManager, &TaskManager::error, _mainWindow,
            &MainWindow::tarsnapError, QUEUED);
    connect(&_notification, &Notification::activated, _mainWindow,
            &MainWindow::notificationRaise, QUEUED);
    connect(&_notification, &Notification::messageClicked, _mainWindow,
            &MainWindow::notificationRaise, QUEUED);
    connect(_mainWindow, &MainWindow::displayNotification, &_notification,
            &Notification::displayNotification, QUEUED);
    connect(_mainWindow, &MainWindow::logMessage, &_journal, &Journal::log,
            QUEUED);
    connect(_mainWindow, &MainWindow::getJournal, &_journal,
            &Journal::getJournal, QUEUED);
    connect(&_journal, &Journal::journal, _mainWindow,
            &MainWindow::setJournal, QUEUED);
    connect(&_journal, &Journal::logEntry, _mainWindow,
            &MainWindow::appendToJournalLog, QUEUED);

    QMetaObject::invokeMethod(_mainWindow, "loadArchives", QUEUED);
    QMetaObject::invokeMethod(_mainWindow, "loadJobs", QUEUED);
    QMetaObject::invokeMethod(_mainWindow, "getJournal", QUEUED);
    _mainWindow->show();
}

bool CoreApplication::reinit()
{
    if(_mainWindow)
    {
        delete _mainWindow;
        _mainWindow = NULL;
    }

    // reset existing persistent store and app settings
    PersistentStore &store = PersistentStore::instance();
    store.purge();

    QSettings settings;
    settings.setDefaultFormat(QSettings::NativeFormat);
    QSettings defaultSettings;
    if(defaultSettings.contains("app/wizard_done"))
    {
        defaultSettings.clear();
        defaultSettings.sync();
    }

    return initialize();
}
<commit_msg>Send TaskManager messages to Journal always.<commit_after>#include "coreapplication.h"
#include "debug.h"
#include "utils.h"
#include "widgets/setupdialog.h"

#include <QDialog>
#include <QFontDatabase>
#include <QMessageBox>

CoreApplication::CoreApplication(int &argc, char **argv)
    : QApplication(argc, argv),
      _mainWindow(NULL),
      _notification(),
      _jobsOption(false)
{
    qRegisterMetaType<TaskStatus>("TaskStatus");
    qRegisterMetaType<QList<QUrl>>("QList<QUrl>");
    qRegisterMetaType<BackupTaskPtr>("BackupTaskPtr");
    qRegisterMetaType<QList<ArchivePtr>>("QList<ArchivePtr >");
    qRegisterMetaType<ArchivePtr>("ArchivePtr");
    qRegisterMetaType<ArchiveRestoreOptions>("ArchiveRestoreOptions");
    qRegisterMetaType<QSqlQuery>("QSqlQuery");
    qRegisterMetaType<JobPtr>("JobPtr");
    qRegisterMetaType<QMap<QString, JobPtr>>("QMap<QString, JobPtr>");
    qRegisterMetaType<QSystemTrayIcon::ActivationReason>("QSystemTrayIcon::ActivationReason");
    qRegisterMetaType<TarsnapError>("TarsnapError");

    QCoreApplication::setOrganizationName(QLatin1String("Tarsnap Backup Inc."));
    QCoreApplication::setOrganizationDomain(QLatin1String("tarsnap.com"));
    QCoreApplication::setApplicationName(QLatin1String("Tarsnap"));
    QCoreApplication::setApplicationVersion(APP_VERSION);
}

CoreApplication::~CoreApplication()
{
    if(_mainWindow)
        delete _mainWindow;
}

void CoreApplication::parseArgs()
{
    QCommandLineParser parser;
    parser.setApplicationDescription(QLatin1String("Tarsnap GUI - Online backups for the truly lazy"));
    parser.addHelpOption();
    parser.addVersionOption();
    QCommandLineOption jobsOption(QStringList() << "j" << "jobs",
                                  tr("Executes all jobs sequentially that have the \'Include in scheduled backups\' option checked."
                                     " The application runs headless and useful information is printed to standard out and error."));
    QCommandLineOption appDataOption(QStringList() << "a" << "appdata",
                                    tr("Use the specified app data directory."
                                       " Useful for multiple configurations on the same machine (INI format is implied)."),
                                    tr("directory"));
    parser.addOption(jobsOption);
    parser.addOption(appDataOption);
    parser.process(arguments());
    _jobsOption = parser.isSet(jobsOption);
    _appDataDir = parser.value(appDataOption);
}

bool CoreApplication::initialize()
{
    parseArgs();

    QSettings settings;

    if(!_appDataDir.isEmpty())
    {
        settings.setPath(QSettings::IniFormat, QSettings::UserScope, _appDataDir);
        settings.setDefaultFormat(QSettings::IniFormat);
    }

    bool wizardDone = settings.value("app/wizard_done", false).toBool();
    if(!wizardDone)
    {
        // Show the first time setup dialog
        SetupDialog wizard;
        connect(&wizard, &SetupDialog::getTarsnapVersion, &_taskManager,
                &TaskManager::getTarsnapVersion);
        connect(&_taskManager, &TaskManager::tarsnapVersion, &wizard,
                &SetupDialog::setTarsnapVersion);
        connect(&wizard, &SetupDialog::requestRegisterMachine, &_taskManager,
                &TaskManager::registerMachine);
        connect(&_taskManager, &TaskManager::registerMachineStatus, &wizard,
                &SetupDialog::registerMachineStatus);
        connect(&_taskManager, &TaskManager::idle, &wizard,
                &SetupDialog::updateLoadingAnimation);

        if(QDialog::Rejected == wizard.exec())
        {
            quit();       // if we're running in the loop
            return false; // if called from main
        }
    }

    bool iniFormat = settings.value("app/ini_format", false).toBool();
    if(iniFormat)
    {
        QString appData = settings.value("app/app_data", APPDATA).toString();
        settings.setPath(QSettings::IniFormat, QSettings::UserScope, appData);
        settings.setDefaultFormat(QSettings::IniFormat);
    }

    connect(&_taskManager, &TaskManager::displayNotification,
            &_notification, &Notification::displayNotification, QUEUED);
    connect(&_taskManager, &TaskManager::message, &_journal, &Journal::log,
            QUEUED);

    QMetaObject::invokeMethod(&_taskManager, "loadSettings", QUEUED);
    QMetaObject::invokeMethod(&_journal, "load", QUEUED);

    if(_jobsOption)
    {
        connect(&_notification, &Notification::activated, this,
                &CoreApplication::showMainWindow, QUEUED);
        connect(&_notification, &Notification::messageClicked, this,
                &CoreApplication::showMainWindow, QUEUED);
        _taskManager.setHeadless(true);
        QMetaObject::invokeMethod(&_taskManager, "runScheduledJobs", QUEUED);
    }
    else
    {
        showMainWindow();
    }

    return true;
}

void CoreApplication::showMainWindow()
{
    if(_mainWindow != NULL)
        return;

    _taskManager.setHeadless(false);
    disconnect(&_notification, &Notification::activated, this,
               &CoreApplication::showMainWindow);
    disconnect(&_notification, &Notification::messageClicked, this,
               &CoreApplication::showMainWindow);

    _mainWindow = new MainWindow();
    Q_ASSERT(_mainWindow != NULL);

    connect(_mainWindow, &MainWindow::getTarsnapVersion, &_taskManager,
            &TaskManager::getTarsnapVersion, QUEUED);
    connect(&_taskManager, &TaskManager::tarsnapVersion, _mainWindow,
            &MainWindow::setTarsnapVersion, QUEUED);
    connect(_mainWindow, &MainWindow::backupNow, &_taskManager,
            &TaskManager::backupNow, QUEUED);
    connect(_mainWindow, &MainWindow::loadArchives, &_taskManager,
            &TaskManager::loadArchives, QUEUED);
    connect(&_taskManager, &TaskManager::archiveList, _mainWindow,
            &MainWindow::archiveList, QUEUED);
    connect(_mainWindow, &MainWindow::deleteArchives, &_taskManager,
            &TaskManager::deleteArchives, QUEUED);
    connect(_mainWindow, &MainWindow::loadArchiveStats, &_taskManager,
            &TaskManager::getArchiveStats, QUEUED);
    connect(_mainWindow, &MainWindow::loadArchiveContents, &_taskManager,
            &TaskManager::getArchiveContents, QUEUED);
    connect(&_taskManager, &TaskManager::idle, _mainWindow,
            &MainWindow::updateLoadingAnimation, QUEUED);
    connect(_mainWindow, &MainWindow::getOverallStats, &_taskManager,
            &TaskManager::getOverallStats, QUEUED);
    connect(&_taskManager, &TaskManager::overallStats, _mainWindow,
            &MainWindow::updateSettingsSummary, QUEUED);
    connect(_mainWindow, &MainWindow::repairCache, &_taskManager,
            &TaskManager::fsck, QUEUED);
    connect(_mainWindow, &MainWindow::settingsChanged, &_taskManager,
            &TaskManager::loadSettings, QUEUED);
    connect(_mainWindow, &MainWindow::purgeArchives, &_taskManager,
            &TaskManager::nuke, QUEUED);
    connect(_mainWindow, &MainWindow::restoreArchive, &_taskManager,
            &TaskManager::restoreArchive, QUEUED);
    connect(_mainWindow, &MainWindow::runSetupWizard, this,
            &CoreApplication::reinit, QUEUED);
    connect(_mainWindow, &MainWindow::stopTasks, &_taskManager,
            &TaskManager::stopTasks, QUEUED);
    connect(_mainWindow, &MainWindow::loadJobs, &_taskManager,
            &TaskManager::loadJobs, QUEUED);
    connect(&_taskManager, &TaskManager::jobsList, _mainWindow,
            &MainWindow::jobsList, QUEUED);
    connect(_mainWindow, &MainWindow::deleteJob, &_taskManager,
            &TaskManager::deleteJob, QUEUED);
    connect(_mainWindow, &MainWindow::getTaskInfo, &_taskManager,
            &TaskManager::getTaskInfo, QUEUED);
    connect(&_taskManager, &TaskManager::taskInfo, _mainWindow,
            &MainWindow::displayStopTasks, QUEUED);
    connect(_mainWindow, &MainWindow::jobAdded, &_taskManager,
            &TaskManager::addJob, QUEUED);
    connect(&_taskManager, &TaskManager::message, _mainWindow,
            &MainWindow::updateStatusMessage, QUEUED);
    connect(&_taskManager, &TaskManager::error, _mainWindow,
            &MainWindow::tarsnapError, QUEUED);
    connect(&_notification, &Notification::activated, _mainWindow,
            &MainWindow::notificationRaise, QUEUED);
    connect(&_notification, &Notification::messageClicked, _mainWindow,
            &MainWindow::notificationRaise, QUEUED);
    connect(_mainWindow, &MainWindow::displayNotification, &_notification,
            &Notification::displayNotification, QUEUED);
    connect(_mainWindow, &MainWindow::logMessage, &_journal, &Journal::log,
            QUEUED);
    connect(_mainWindow, &MainWindow::getJournal, &_journal,
            &Journal::getJournal, QUEUED);
    connect(&_journal, &Journal::journal, _mainWindow,
            &MainWindow::setJournal, QUEUED);
    connect(&_journal, &Journal::logEntry, _mainWindow,
            &MainWindow::appendToJournalLog, QUEUED);

    QMetaObject::invokeMethod(_mainWindow, "loadArchives", QUEUED);
    QMetaObject::invokeMethod(_mainWindow, "loadJobs", QUEUED);
    QMetaObject::invokeMethod(_mainWindow, "getJournal", QUEUED);
    _mainWindow->show();
}

bool CoreApplication::reinit()
{
    if(_mainWindow)
    {
        delete _mainWindow;
        _mainWindow = NULL;
    }

    // reset existing persistent store and app settings
    PersistentStore &store = PersistentStore::instance();
    store.purge();

    QSettings settings;
    settings.setDefaultFormat(QSettings::NativeFormat);
    QSettings defaultSettings;
    if(defaultSettings.contains("app/wizard_done"))
    {
        defaultSettings.clear();
        defaultSettings.sync();
    }

    return initialize();
}
<|endoftext|>