<commit_before>/*
 * Copyright (c) 2008, Thomas Jaeger <ThJaeger@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include "actions.h"
#include "prefs.h"
#include "stats.h"
#include "win.h"
#include "main.h"
#include "grabber.h"

Glib::RefPtr<Gtk::Builder> widgets;

void Stroke::draw(Cairo::RefPtr<Cairo::Surface> surface, int x, int y, int w, int h, bool big) const {
	const Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create (surface);
	x+=2; y+=2; w -= 4; h -= 4;
	ctx->save();
	ctx->translate(x,y);
	ctx->scale(w,h);
	ctx->set_line_width((big ? 8.0 : 4.0)/(w+h));
	if (size()) {
		ctx->set_line_cap(Cairo::LINE_CAP_ROUND);
		int n = points.size();
		float lambda = sqrt(3)-2.0;
		float sum = lambda / (1 - lambda);
		std::vector<Point> y(n);
		y[0].x = sum * points[0].x;
		y[0].y = sum * points[0].y;
		for (int j = 0; j < n-1; j++) {
			y[j+1].x = lambda * (y[j].x + points[j].x);
			y[j+1].y = lambda * (y[j].y + points[j].y);
		}
		std::vector<Point> z(n);
		z[n-1].x = -1.0 * sum * points[n-1].x;
		z[n-1].y = -1.0 * sum * points[n-1].y;
		for (int j = n-1; j > 0; j--) {
			z[j-1].x = lambda * (z[j].x - points[j].x);
			z[j-1].y = lambda * (z[j].y - points[j].y);
		}
		for (int j = 0; j < n-1; j++) {
			// j -> j+1
			ctx->set_source_rgba(0, points[j].time, 1-points[j].time, 1);
			ctx->move_to(points[j].x, points[j].y);
			ctx->curve_to(
					points[j].x + y[j].x + z[j].x,
					points[j].y + y[j].y + z[j].y,
					points[j+1].x - y[j+1].x - z[j+1].x,
					points[j+1].y - y[j+1].y - z[j+1].y,
					points[j+1].x,
					points[j+1].y);
			ctx->stroke();
		}
	} else if (!button) {
		ctx->set_source_rgba(0, 0, 1, 1);
		ctx->move_to(0.33, 0.33);
		ctx->line_to(0.67, 0.67);
		ctx->move_to(0.33, 0.67);
		ctx->line_to(0.67, 0.33);
		ctx->stroke();
	}
	ctx->restore();
	if (!button && !timeout)
		return;
	ctx->set_source_rgba(1, 0, 0, 0.8);
	Glib::ustring str = timeout ? "x" : Glib::ustring::format(button);
	ctx->set_font_size(h*0.6);
	Cairo::TextExtents te;
	ctx->get_text_extents(str, te);
	ctx->move_to(x+w/2 - te.x_bearing - te.width/2, y+h/2 - te.y_bearing - te.height/2);
	ctx->show_text(str);
}

void Stroke::draw_svg(std::string filename) const {
	const int S = 32;
	const int B = 1;
	Cairo::RefPtr<Cairo::SvgSurface> s = Cairo::SvgSurface::create(filename, S, S);
	draw(s, B, B, S-2*B, S-2*B, false);
}

Glib::RefPtr<Gdk::Pixbuf> Stroke::draw_(int size, bool big) const {
	Glib::RefPtr<Gdk::Pixbuf> pb = drawEmpty_(size);
	int w = size;
	int h = size;
	int stride = pb->get_rowstride();
	guint8 *row = pb->get_pixels();
	// This is all pretty messed up
	// http://www.archivum.info/gtkmm-list@gnome.org/2007-05/msg00112.html
	Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(row, Cairo::FORMAT_ARGB32, w, h, stride);
	draw(surface, 0, 0, pb->get_width(), size, big);
	for (int i = 0; i < w; i++) {
		guint8 *px = row;
		for (int j = 0; j < h; j++) {
			guint8 a = px[3];
			guint8 r = px[2];
			guint8 g = px[1];
			guint8 b = px[0];

			if (a) {
				px[0] = ((((guint)r) << 8) - r) / a;
				px[1] = ((((guint)g) << 8) - g) / a;
				px[2] = ((((guint)b) << 8) - b) / a;
			}
			px += 4;
		}
		row += stride;
	}
	return pb;
}

Glib::RefPtr<Gdk::Pixbuf> Stroke::drawEmpty_(int size) {
	Glib::RefPtr<Gdk::Pixbuf> pb = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,true,8,size,size);
	pb->fill(0x00000000);
	return pb;
}

extern const char *gui_buffer;

int run_dialog(const char *str) {
	Glib::RefPtr<Gtk::Builder> xml = Gtk::Builder::create_from_string(gui_buffer);
	Gtk::Dialog *dialog;
	xml->get_widget(str, dialog);
	int response = dialog->run();
	dialog->hide();
	return response;
}

Win::Win() {
	widgets = Gtk::Builder::create_from_string(gui_buffer),
	actions = new Actions;
	prefs_tab = new Prefs;
	stats = new Stats;

	show_hide_icon();
	prefs.tray_icon.connect(new Notifier(sigc::mem_fun(*this, &Win::show_hide_icon)));

	WIDGET(Gtk::CheckMenuItem, menu_disabled, "D_isabled", true);
	this->menu_disabled = &menu_disabled;
	menu.append(menu_disabled);
	menu_disabled.signal_toggled().connect(sigc::mem_fun(*grabber, &Grabber::toggle_disabled));
	WIDGET(Gtk::ImageMenuItem, menu_quit, Gtk::Stock::QUIT);
	menu.append(menu_quit);
	menu_quit.signal_activate().connect(sigc::ptr_fun(&Gtk::Main::quit));
	menu.show_all();

	widgets->get_widget("main", win);
	RStroke trefoil = Stroke::trefoil();
	std::vector<Glib::RefPtr<Gdk::Pixbuf> > icons;
	icons.push_back(trefoil->draw(24));
	icons.push_back(trefoil->draw(64));
	win->set_icon_list(icons);

	Gtk::Button* button_hide[4];
	widgets->get_widget("button_hide1", button_hide[0]);
	widgets->get_widget("button_hide2", button_hide[1]);
	widgets->get_widget("button_hide3", button_hide[2]);
	widgets->get_widget("button_hide4", button_hide[3]);
	for (int i = 0; i < 4; i++)
		button_hide[i]->signal_clicked().connect(sigc::mem_fun(win, &Gtk::Window::hide));
}

Win::~Win() {
	delete actions;
	delete prefs_tab;
	delete stats;
}

void Win::toggle_disabled() {
	bool disabled = menu_disabled->get_active();
	menu_disabled->set_active(!disabled);
}

void Win::show_hide_icon() {
	bool show = prefs.tray_icon.get();
	if (show) {
		if (icon)
			return;
		icon = Gtk::StatusIcon::create("");
		icon->signal_size_changed().connect(sigc::mem_fun(*this, &Win::on_icon_size_changed));
		icon->signal_activate().connect(sigc::mem_fun(*this, &Win::show_hide));
		icon->signal_popup_menu().connect(sigc::mem_fun(*this, &Win::show_popup));
	} else {
		if (!icon)
			return;
		icon.reset();
	}
}

void Win::show_popup(guint button, guint32 activate_time) {
	icon->popup_menu_at_position(menu, button, activate_time);
}

void Win::show_hide() {
	if (win->is_mapped())
		win->hide();
	else
		win->show();
}

bool Win::on_icon_size_changed(int size) {
	icon->set(Stroke::trefoil()->draw(size));
	return true;
}

FormatLabel::FormatLabel(Glib::RefPtr<Gtk::Builder> builder, Glib::ustring name, ...) {
	builder->get_widget(name, label);
	oldstring = label->get_label();
	char newstring[256];
	va_list argp;
	va_start(argp, name);
	vsnprintf(newstring, 255, oldstring.c_str(), argp);
	va_end(argp);
	label->set_label(newstring);
	label->set_use_markup();
}

FormatLabel::~FormatLabel() {
	label->set_text(oldstring);
}

ErrorDialog::ErrorDialog(const Glib::ustring &text) :
		MessageDialog(win->get_window(), text, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true)
	{ show(); }
<commit_msg>Always raise after showing the config window This works around what is probably a compiz bug.<commit_after>/*
 * Copyright (c) 2008, Thomas Jaeger <ThJaeger@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#include "actions.h"
#include "prefs.h"
#include "stats.h"
#include "win.h"
#include "main.h"
#include "grabber.h"

Glib::RefPtr<Gtk::Builder> widgets;

void Stroke::draw(Cairo::RefPtr<Cairo::Surface> surface, int x, int y, int w, int h, bool big) const {
	const Cairo::RefPtr<Cairo::Context> ctx = Cairo::Context::create (surface);
	x+=2; y+=2; w -= 4; h -= 4;
	ctx->save();
	ctx->translate(x,y);
	ctx->scale(w,h);
	ctx->set_line_width((big ? 8.0 : 4.0)/(w+h));
	if (size()) {
		ctx->set_line_cap(Cairo::LINE_CAP_ROUND);
		int n = points.size();
		float lambda = sqrt(3)-2.0;
		float sum = lambda / (1 - lambda);
		std::vector<Point> y(n);
		y[0].x = sum * points[0].x;
		y[0].y = sum * points[0].y;
		for (int j = 0; j < n-1; j++) {
			y[j+1].x = lambda * (y[j].x + points[j].x);
			y[j+1].y = lambda * (y[j].y + points[j].y);
		}
		std::vector<Point> z(n);
		z[n-1].x = -1.0 * sum * points[n-1].x;
		z[n-1].y = -1.0 * sum * points[n-1].y;
		for (int j = n-1; j > 0; j--) {
			z[j-1].x = lambda * (z[j].x - points[j].x);
			z[j-1].y = lambda * (z[j].y - points[j].y);
		}
		for (int j = 0; j < n-1; j++) {
			// j -> j+1
			ctx->set_source_rgba(0, points[j].time, 1-points[j].time, 1);
			ctx->move_to(points[j].x, points[j].y);
			ctx->curve_to(
					points[j].x + y[j].x + z[j].x,
					points[j].y + y[j].y + z[j].y,
					points[j+1].x - y[j+1].x - z[j+1].x,
					points[j+1].y - y[j+1].y - z[j+1].y,
					points[j+1].x,
					points[j+1].y);
			ctx->stroke();
		}
	} else if (!button) {
		ctx->set_source_rgba(0, 0, 1, 1);
		ctx->move_to(0.33, 0.33);
		ctx->line_to(0.67, 0.67);
		ctx->move_to(0.33, 0.67);
		ctx->line_to(0.67, 0.33);
		ctx->stroke();
	}
	ctx->restore();
	if (!button && !timeout)
		return;
	ctx->set_source_rgba(1, 0, 0, 0.8);
	Glib::ustring str = timeout ? "x" : Glib::ustring::format(button);
	ctx->set_font_size(h*0.6);
	Cairo::TextExtents te;
	ctx->get_text_extents(str, te);
	ctx->move_to(x+w/2 - te.x_bearing - te.width/2, y+h/2 - te.y_bearing - te.height/2);
	ctx->show_text(str);
}

void Stroke::draw_svg(std::string filename) const {
	const int S = 32;
	const int B = 1;
	Cairo::RefPtr<Cairo::SvgSurface> s = Cairo::SvgSurface::create(filename, S, S);
	draw(s, B, B, S-2*B, S-2*B, false);
}

Glib::RefPtr<Gdk::Pixbuf> Stroke::draw_(int size, bool big) const {
	Glib::RefPtr<Gdk::Pixbuf> pb = drawEmpty_(size);
	int w = size;
	int h = size;
	int stride = pb->get_rowstride();
	guint8 *row = pb->get_pixels();
	// This is all pretty messed up
	// http://www.archivum.info/gtkmm-list@gnome.org/2007-05/msg00112.html
	Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(row, Cairo::FORMAT_ARGB32, w, h, stride);
	draw(surface, 0, 0, pb->get_width(), size, big);
	for (int i = 0; i < w; i++) {
		guint8 *px = row;
		for (int j = 0; j < h; j++) {
			guint8 a = px[3];
			guint8 r = px[2];
			guint8 g = px[1];
			guint8 b = px[0];

			if (a) {
				px[0] = ((((guint)r) << 8) - r) / a;
				px[1] = ((((guint)g) << 8) - g) / a;
				px[2] = ((((guint)b) << 8) - b) / a;
			}
			px += 4;
		}
		row += stride;
	}
	return pb;
}

Glib::RefPtr<Gdk::Pixbuf> Stroke::drawEmpty_(int size) {
	Glib::RefPtr<Gdk::Pixbuf> pb = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,true,8,size,size);
	pb->fill(0x00000000);
	return pb;
}

extern const char *gui_buffer;

int run_dialog(const char *str) {
	Glib::RefPtr<Gtk::Builder> xml = Gtk::Builder::create_from_string(gui_buffer);
	Gtk::Dialog *dialog;
	xml->get_widget(str, dialog);
	int response = dialog->run();
	dialog->hide();
	return response;
}

Win::Win() {
	widgets = Gtk::Builder::create_from_string(gui_buffer),
	actions = new Actions;
	prefs_tab = new Prefs;
	stats = new Stats;

	show_hide_icon();
	prefs.tray_icon.connect(new Notifier(sigc::mem_fun(*this, &Win::show_hide_icon)));

	WIDGET(Gtk::CheckMenuItem, menu_disabled, "D_isabled", true);
	this->menu_disabled = &menu_disabled;
	menu.append(menu_disabled);
	menu_disabled.signal_toggled().connect(sigc::mem_fun(*grabber, &Grabber::toggle_disabled));
	WIDGET(Gtk::ImageMenuItem, menu_quit, Gtk::Stock::QUIT);
	menu.append(menu_quit);
	menu_quit.signal_activate().connect(sigc::ptr_fun(&Gtk::Main::quit));
	menu.show_all();

	widgets->get_widget("main", win);
	RStroke trefoil = Stroke::trefoil();
	std::vector<Glib::RefPtr<Gdk::Pixbuf> > icons;
	icons.push_back(trefoil->draw(24));
	icons.push_back(trefoil->draw(64));
	win->set_icon_list(icons);

	Gtk::Button* button_hide[4];
	widgets->get_widget("button_hide1", button_hide[0]);
	widgets->get_widget("button_hide2", button_hide[1]);
	widgets->get_widget("button_hide3", button_hide[2]);
	widgets->get_widget("button_hide4", button_hide[3]);
	for (int i = 0; i < 4; i++)
		button_hide[i]->signal_clicked().connect(sigc::mem_fun(win, &Gtk::Window::hide));
}

Win::~Win() {
	delete actions;
	delete prefs_tab;
	delete stats;
}

void Win::toggle_disabled() {
	bool disabled = menu_disabled->get_active();
	menu_disabled->set_active(!disabled);
}

void Win::show_hide_icon() {
	bool show = prefs.tray_icon.get();
	if (show) {
		if (icon)
			return;
		icon = Gtk::StatusIcon::create("");
		icon->signal_size_changed().connect(sigc::mem_fun(*this, &Win::on_icon_size_changed));
		icon->signal_activate().connect(sigc::mem_fun(*this, &Win::show_hide));
		icon->signal_popup_menu().connect(sigc::mem_fun(*this, &Win::show_popup));
	} else {
		if (!icon)
			return;
		icon.reset();
	}
}

void Win::show_popup(guint button, guint32 activate_time) {
	icon->popup_menu_at_position(menu, button, activate_time);
}

void Win::show_hide() {
	if (win->is_mapped()) {
		win->hide();
	} else {
		win->show();
		win->raise();
	}
}

bool Win::on_icon_size_changed(int size) {
	icon->set(Stroke::trefoil()->draw(size));
	return true;
}

FormatLabel::FormatLabel(Glib::RefPtr<Gtk::Builder> builder, Glib::ustring name, ...) {
	builder->get_widget(name, label);
	oldstring = label->get_label();
	char newstring[256];
	va_list argp;
	va_start(argp, name);
	vsnprintf(newstring, 255, oldstring.c_str(), argp);
	va_end(argp);
	label->set_label(newstring);
	label->set_use_markup();
}

FormatLabel::~FormatLabel() {
	label->set_text(oldstring);
}

ErrorDialog::ErrorDialog(const Glib::ustring &text) :
		MessageDialog(win->get_window(), text, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true)
	{ show(); }
<|endoftext|>


<commit_before>#include "glcontext.hpp"

#include <cassert>
#include <tchar.h>
#include <iostream>
#include <GL/wglew.h>

using namespace std;
using namespace gl_util;

class glcontext::priv::detail
{
public:

    bool init
    (
        GLint gl_req_major_ver,
        GLint gl_req_minor_ver
    );

    ~detail();

private:

    HWND	hWnd    = 0;
    HDC		hdc     = 0;
    HGLRC	hglrc   = 0;
};

glcontext::priv::priv():
    pimpl(make_unique<detail>())
{
}

glcontext::priv::~priv()
{
}

bool glcontext::priv::init
(
    GLint gl_req_major_ver,
    GLint gl_req_minor_ver
)
{
    return pimpl->init(gl_req_major_ver, gl_req_minor_ver);
}

bool glcontext::init
(
	GLint gl_req_major_ver,
	GLint gl_req_minor_ver
)
{
    return true;
}

bool glcontext::priv::detail::init
(
    GLint gl_req_major_ver,
    GLint gl_req_minor_ver
)
{
    assert(hWnd == 0 && hdc == 0 && hglrc == 0);

    hWnd =
        CreateWindowEx(
            WS_EX_APPWINDOW, _T("STATIC"),
            _T("dummy"), WS_POPUP, 0, 0,
            640, 480, NULL, NULL, GetModuleHandle(0), NULL);

    if(!hWnd)
    {
        cerr << "Failed to CreateWindowEx" << endl;
        return false;
    }

//  ShowWindow(hWnd, SW_SHOW);

    hdc = GetDC(hWnd);

    const static PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd
        1,                     // version number
        PFD_DRAW_TO_WINDOW |   // support window
        PFD_SUPPORT_OPENGL |   // support OpenGL
        PFD_DOUBLEBUFFER,      // double buffered
        PFD_TYPE_RGBA,         // RGBA type
        32,                    // color depth
        0, 0, 0, 0, 0, 0,      // color bits ignored
        0,                     // no alpha buffer
        0,                     // shift bit ignored
        0,                     // no accumulation buffer
        0, 0, 0, 0,            // accum bits ignored
        0, //24,                    // z-buffer bits
        0,                     // stencil buffer bits
        0,                     // no auxiliary buffer
        PFD_MAIN_PLANE,        // main layer
        0,                     // reserved
        0, 0, 0                // layer masks ignored
    };

    int  iPixelFormat = ChoosePixelFormat(hdc, &pfd);
    if(!iPixelFormat)
    {
        return false;
    }

    if(SetPixelFormat(hdc, iPixelFormat, &pfd)==FALSE)
    {
        return false;
    }

    HGLRC tmpCntxt = wglCreateContext(hdc);
    if(tmpCntxt==0)
    {
        cerr << "Failed to wglCreateContext\n";
        return false;
    }

    wglMakeCurrent(hdc, tmpCntxt);

#if 0
    const static int attribList[] =
    {
        WGL_DRAW_TO_WINDOW_ARB,     GL_TRUE,
        WGL_ACCELERATION_ARB,       WGL_FULL_ACCELERATION_ARB,
        WGL_SUPPORT_OPENGL_ARB,     GL_TRUE,
        WGL_DOUBLE_BUFFER_ARB,      GL_TRUE,
        WGL_PIXEL_TYPE_ARB,         WGL_TYPE_RGBA_ARB,
        WGL_COLOR_BITS_ARB,         32,
        WGL_DEPTH_BITS_ARB,         24,
        0
    };
    int pixelFormat, numFormats;
    if(
        wglChoosePixelFormatARB(
            hdc, attribList, NULL, 1, &pixelFormat, &numFormats)
        ==
        FALSE)
    {
        cerr << "Failed to wglChoosePixelFormatARB" << endl;
        return false;
    }

    if(SetPixelFormat(hdc, pixelFormat, &pfd)==FALSE)
    {
        return false;
    }
#endif

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        cerr << "Failed to glewInit\n";
        return false;
    }

    const static int attribList[] =
    {
        WGL_CONTEXT_MAJOR_VERSION_ARB, gl_req_major_ver,
        WGL_CONTEXT_MINOR_VERSION_ARB, gl_req_minor_ver,
        WGL_CONTEXT_FLAGS_ARB,
        WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB |
#ifdef NDEBUG
        0
#else
        WGL_CONTEXT_DEBUG_BIT_ARB
#endif
        ,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
        0
    };

    if(wglewIsSupported("WGL_ARB_create_context") == 1)
    {
        hglrc = wglCreateContextAttribsARB(hdc, 0, attribList);
        if(hglrc == 0)
        {
            cerr << "Failed to wglCreateContextAttribsARB\n";
            wglMakeCurrent(NULL,NULL);
            wglDeleteContext(tmpCntxt);
            return false;
        }

        wglMakeCurrent(NULL,NULL);
        wglDeleteContext(tmpCntxt);
        wglMakeCurrent(hdc, hglrc);
    }else
    {
        hglrc = tmpCntxt;
    }

    return true;
}

void glcontext::uninit()
{
}

glcontext::priv::detail::~detail()
{
    wglMakeCurrent(NULL, NULL);

    if(hglrc)
        wglDeleteContext(hglrc);

    if(hdc)
        ReleaseDC(hWnd, hdc);

    if(hWnd)
        DestroyWindow(hWnd);
}
<commit_msg>Removed unused code<commit_after>#include "glcontext.hpp"

#include <cassert>
#include <tchar.h>
#include <iostream>
#include <GL/wglew.h>

using namespace std;
using namespace gl_util;

class glcontext::priv::detail
{
public:

    bool init
    (
        GLint gl_req_major_ver,
        GLint gl_req_minor_ver
    );

    ~detail();

private:

    HWND	hWnd    = 0;
    HDC		hdc     = 0;
    HGLRC	hglrc   = 0;
};

glcontext::priv::priv():
    pimpl(make_unique<detail>())
{
}

glcontext::priv::~priv()
{
}

bool glcontext::priv::init
(
    GLint gl_req_major_ver,
    GLint gl_req_minor_ver
)
{
    return pimpl->init(gl_req_major_ver, gl_req_minor_ver);
}

bool glcontext::priv::detail::init
(
    GLint gl_req_major_ver,
    GLint gl_req_minor_ver
)
{
    assert(hWnd == 0 && hdc == 0 && hglrc == 0);

    hWnd =
        CreateWindowEx(
            WS_EX_APPWINDOW, _T("STATIC"),
            _T("dummy"), WS_POPUP, 0, 0,
            640, 480, NULL, NULL, GetModuleHandle(0), NULL);

    if(!hWnd)
    {
        cerr << "Failed to CreateWindowEx" << endl;
        return false;
    }

//  ShowWindow(hWnd, SW_SHOW);

    hdc = GetDC(hWnd);

    const static PIXELFORMATDESCRIPTOR pfd = {
        sizeof(PIXELFORMATDESCRIPTOR),  //  size of this pfd
        1,                     // version number
        PFD_DRAW_TO_WINDOW |   // support window
        PFD_SUPPORT_OPENGL |   // support OpenGL
        PFD_DOUBLEBUFFER,      // double buffered
        PFD_TYPE_RGBA,         // RGBA type
        32,                    // color depth
        0, 0, 0, 0, 0, 0,      // color bits ignored
        0,                     // no alpha buffer
        0,                     // shift bit ignored
        0,                     // no accumulation buffer
        0, 0, 0, 0,            // accum bits ignored
        0, //24,                    // z-buffer bits
        0,                     // stencil buffer bits
        0,                     // no auxiliary buffer
        PFD_MAIN_PLANE,        // main layer
        0,                     // reserved
        0, 0, 0                // layer masks ignored
    };

    int  iPixelFormat = ChoosePixelFormat(hdc, &pfd);
    if(!iPixelFormat)
    {
        return false;
    }

    if(SetPixelFormat(hdc, iPixelFormat, &pfd)==FALSE)
    {
        return false;
    }

    HGLRC tmpCntxt = wglCreateContext(hdc);
    if(tmpCntxt==0)
    {
        cerr << "Failed to wglCreateContext\n";
        return false;
    }

    wglMakeCurrent(hdc, tmpCntxt);

#if 0
    const static int attribList[] =
    {
        WGL_DRAW_TO_WINDOW_ARB,     GL_TRUE,
        WGL_ACCELERATION_ARB,       WGL_FULL_ACCELERATION_ARB,
        WGL_SUPPORT_OPENGL_ARB,     GL_TRUE,
        WGL_DOUBLE_BUFFER_ARB,      GL_TRUE,
        WGL_PIXEL_TYPE_ARB,         WGL_TYPE_RGBA_ARB,
        WGL_COLOR_BITS_ARB,         32,
        WGL_DEPTH_BITS_ARB,         24,
        0
    };
    int pixelFormat, numFormats;
    if(
        wglChoosePixelFormatARB(
            hdc, attribList, NULL, 1, &pixelFormat, &numFormats)
        ==
        FALSE)
    {
        cerr << "Failed to wglChoosePixelFormatARB" << endl;
        return false;
    }

    if(SetPixelFormat(hdc, pixelFormat, &pfd)==FALSE)
    {
        return false;
    }
#endif

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        cerr << "Failed to glewInit\n";
        return false;
    }

    const static int attribList[] =
    {
        WGL_CONTEXT_MAJOR_VERSION_ARB, gl_req_major_ver,
        WGL_CONTEXT_MINOR_VERSION_ARB, gl_req_minor_ver,
        WGL_CONTEXT_FLAGS_ARB,
        WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB |
#ifdef NDEBUG
        0
#else
        WGL_CONTEXT_DEBUG_BIT_ARB
#endif
        ,
        WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
        0
    };

    if(wglewIsSupported("WGL_ARB_create_context") == 1)
    {
        hglrc = wglCreateContextAttribsARB(hdc, 0, attribList);
        if(hglrc == 0)
        {
            cerr << "Failed to wglCreateContextAttribsARB\n";
            wglMakeCurrent(NULL,NULL);
            wglDeleteContext(tmpCntxt);
            return false;
        }

        wglMakeCurrent(NULL,NULL);
        wglDeleteContext(tmpCntxt);
        wglMakeCurrent(hdc, hglrc);
    }else
    {
        hglrc = tmpCntxt;
    }

    return true;
}

glcontext::priv::detail::~detail()
{
    wglMakeCurrent(NULL, NULL);

    if(hglrc)
        wglDeleteContext(hglrc);

    if(hdc)
        ReleaseDC(hWnd, hdc);

    if(hWnd)
        DestroyWindow(hWnd);
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

#include "ast.h"

void
ast_type_specifier::print(void) const
{
   if (structure) {
      structure->print();
   } else {
      printf("%s ", type_name);
   }

   if (array_specifier) {
      array_specifier->print();
   }
}

bool
ast_fully_specified_type::has_qualifiers() const
{
   return this->qualifier.flags.i != 0;
}

bool ast_type_qualifier::has_interpolation() const
{
   return this->flags.q.smooth
          || this->flags.q.flat
          || this->flags.q.noperspective;
}

bool
ast_type_qualifier::has_layout() const
{
   return this->flags.q.origin_upper_left
          || this->flags.q.pixel_center_integer
          || this->flags.q.depth_any
          || this->flags.q.depth_greater
          || this->flags.q.depth_less
          || this->flags.q.depth_unchanged
          || this->flags.q.std140
          || this->flags.q.shared
          || this->flags.q.column_major
          || this->flags.q.row_major
          || this->flags.q.packed
          || this->flags.q.explicit_location
          || this->flags.q.explicit_index
          || this->flags.q.explicit_binding
          || this->flags.q.explicit_offset;
}

bool
ast_type_qualifier::has_storage() const
{
   return this->flags.q.constant
          || this->flags.q.attribute
          || this->flags.q.varying
          || this->flags.q.in
          || this->flags.q.out
          || this->flags.q.uniform;
}

bool
ast_type_qualifier::has_auxiliary_storage() const
{
   return this->flags.q.centroid
          || this->flags.q.sample;
}

const char*
ast_type_qualifier::interpolation_string() const
{
   if (this->flags.q.smooth)
      return "smooth";
   else if (this->flags.q.flat)
      return "flat";
   else if (this->flags.q.noperspective)
      return "noperspective";
   else
      return NULL;
}

bool
ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
				    _mesa_glsl_parse_state *state,
				    ast_type_qualifier q)
{
   ast_type_qualifier ubo_mat_mask;
   ubo_mat_mask.flags.i = 0;
   ubo_mat_mask.flags.q.row_major = 1;
   ubo_mat_mask.flags.q.column_major = 1;

   ast_type_qualifier ubo_layout_mask;
   ubo_layout_mask.flags.i = 0;
   ubo_layout_mask.flags.q.std140 = 1;
   ubo_layout_mask.flags.q.packed = 1;
   ubo_layout_mask.flags.q.shared = 1;

   ast_type_qualifier ubo_binding_mask;
   ubo_binding_mask.flags.i = 0;
   ubo_binding_mask.flags.q.explicit_binding = 1;
   ubo_binding_mask.flags.q.explicit_offset = 1;

   ast_type_qualifier stream_layout_mask;
   stream_layout_mask.flags.i = 0;
   stream_layout_mask.flags.q.stream = 1;

   /* Uniform block layout qualifiers get to overwrite each
    * other (rightmost having priority), while all other
    * qualifiers currently don't allow duplicates.
    */
   ast_type_qualifier allowed_duplicates_mask;
   allowed_duplicates_mask.flags.i =
      ubo_mat_mask.flags.i |
      ubo_layout_mask.flags.i |
      ubo_binding_mask.flags.i;

   /* Geometry shaders can have several layout qualifiers
    * assigning different stream values.
    */
   if (state->stage == MESA_SHADER_GEOMETRY)
      allowed_duplicates_mask.flags.i |=
         stream_layout_mask.flags.i;

   if ((this->flags.i & q.flags.i & ~allowed_duplicates_mask.flags.i) != 0) {
      _mesa_glsl_error(loc, state,
		       "duplicate layout qualifiers used");
      return false;
   }

   if (q.flags.q.prim_type) {
      if (this->flags.q.prim_type && this->prim_type != q.prim_type) {
	 _mesa_glsl_error(loc, state,
			  "conflicting primitive type qualifiers used");
	 return false;
      }
      this->prim_type = q.prim_type;
   }

   if (q.flags.q.max_vertices) {
      if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) {
	 _mesa_glsl_error(loc, state,
			  "geometry shader set conflicting max_vertices "
			  "(%d and %d)", this->max_vertices, q.max_vertices);
	 return false;
      }
      this->max_vertices = q.max_vertices;
   }

   if (state->stage == MESA_SHADER_GEOMETRY &&
       state->has_explicit_attrib_stream()) {
      if (q.flags.q.stream && q.stream >= state->ctx->Const.MaxVertexStreams) {
         _mesa_glsl_error(loc, state,
                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
                          "(%d > %d)",
                          q.stream, state->ctx->Const.MaxVertexStreams - 1);
      }
      if (this->flags.q.explicit_stream &&
          this->stream >= state->ctx->Const.MaxVertexStreams) {
         _mesa_glsl_error(loc, state,
                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
                          "(%d > %d)",
                          this->stream, state->ctx->Const.MaxVertexStreams - 1);
      }

      if (!this->flags.q.explicit_stream) {
         if (q.flags.q.stream) {
            this->flags.q.stream = 1;
            this->stream = q.stream;
         } else if (!this->flags.q.stream && this->flags.q.out) {
            /* Assign default global stream value */
            this->flags.q.stream = 1;
            this->stream = state->out_qualifier->stream;
         }
      } else {
         if (q.flags.q.explicit_stream) {
            _mesa_glsl_error(loc, state,
                             "duplicate layout `stream' qualifier");
         }
      }
   }

   if ((q.flags.i & ubo_mat_mask.flags.i) != 0)
      this->flags.i &= ~ubo_mat_mask.flags.i;
   if ((q.flags.i & ubo_layout_mask.flags.i) != 0)
      this->flags.i &= ~ubo_layout_mask.flags.i;

   for (int i = 0; i < 3; i++) {
      if (q.flags.q.local_size & (1 << i)) {
         if ((this->flags.q.local_size & (1 << i)) &&
             this->local_size[i] != q.local_size[i]) {
            _mesa_glsl_error(loc, state,
                             "compute shader set conflicting values for "
                             "local_size_%c (%d and %d)", 'x' + i,
                             this->local_size[i], q.local_size[i]);
            return false;
         }
         this->local_size[i] = q.local_size[i];
      }
   }

   this->flags.i |= q.flags.i;

   if (q.flags.q.explicit_location)
      this->location = q.location;

   if (q.flags.q.explicit_index)
      this->index = q.index;

   if (q.flags.q.explicit_binding)
      this->binding = q.binding;

   if (q.flags.q.explicit_offset)
      this->offset = q.offset;

   if (q.precision != ast_precision_none)
      this->precision = q.precision;

   if (q.flags.q.explicit_image_format) {
      this->image_format = q.image_format;
      this->image_base_type = q.image_base_type;
   }

   return true;
}

bool
ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
                                       _mesa_glsl_parse_state *state,
                                       ast_type_qualifier q,
                                       ast_node* &node)
{
   void *mem_ctx = state;
   bool create_gs_ast = false;
   bool create_cs_ast = false;
   ast_type_qualifier valid_in_mask;
   valid_in_mask.flags.i = 0;

   switch (state->stage) {
   case MESA_SHADER_GEOMETRY:
      if (q.flags.q.prim_type) {
         /* Make sure this is a valid input primitive type. */
         switch (q.prim_type) {
         case GL_POINTS:
         case GL_LINES:
         case GL_LINES_ADJACENCY:
         case GL_TRIANGLES:
         case GL_TRIANGLES_ADJACENCY:
            break;
         default:
            _mesa_glsl_error(loc, state,
                             "invalid geometry shader input primitive type");
            break;
         }
      }

      create_gs_ast |=
         q.flags.q.prim_type &&
         !state->in_qualifier->flags.q.prim_type;

      valid_in_mask.flags.q.prim_type = 1;
      valid_in_mask.flags.q.invocations = 1;
      break;
   case MESA_SHADER_FRAGMENT:
      if (q.flags.q.early_fragment_tests) {
         state->early_fragment_tests = true;
      } else {
         _mesa_glsl_error(loc, state, "invalid input layout qualifier");
      }
      break;
   case MESA_SHADER_COMPUTE:
      create_cs_ast |=
         q.flags.q.local_size != 0 &&
         state->in_qualifier->flags.q.local_size == 0;

      valid_in_mask.flags.q.local_size = 7;
      break;
   default:
      _mesa_glsl_error(loc, state,
                       "input layout qualifiers only valid in "
                       "geometry, fragment and compute shaders");
      break;
   }

   /* Generate an error when invalid input layout qualifiers are used. */
   if ((q.flags.i & ~valid_in_mask.flags.i) != 0) {
      _mesa_glsl_error(loc, state,
		       "invalid input layout qualifiers used");
      return false;
   }

   /* Input layout qualifiers can be specified multiple
    * times in separate declarations, as long as they match.
    */
   if (this->flags.q.prim_type) {
      if (q.flags.q.prim_type &&
          this->prim_type != q.prim_type) {
         _mesa_glsl_error(loc, state,
                          "conflicting input primitive types specified");
      }
   } else if (q.flags.q.prim_type) {
      state->in_qualifier->flags.q.prim_type = 1;
      state->in_qualifier->prim_type = q.prim_type;
   }

   if (this->flags.q.invocations &&
       q.flags.q.invocations &&
       this->invocations != q.invocations) {
      _mesa_glsl_error(loc, state,
                       "conflicting invocations counts specified");
      return false;
   } else if (q.flags.q.invocations) {
      this->flags.q.invocations = 1;
      this->invocations = q.invocations;
   }

   if (create_gs_ast) {
      node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
   } else if (create_cs_ast) {
      /* Infer a local_size of 1 for every unspecified dimension */
      unsigned local_size[3];
      for (int i = 0; i < 3; i++) {
         if (q.flags.q.local_size & (1 << i))
            local_size[i] = q.local_size[i];
         else
            local_size[i] = 1;
      }
      node = new(mem_ctx) ast_cs_input_layout(*loc, local_size);
   }

   return true;
}
<commit_msg>glsl: Fix merging of layout(invocations) with other qualifiers<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * 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 (including the next
 * paragraph) 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.
 */

#include "ast.h"

void
ast_type_specifier::print(void) const
{
   if (structure) {
      structure->print();
   } else {
      printf("%s ", type_name);
   }

   if (array_specifier) {
      array_specifier->print();
   }
}

bool
ast_fully_specified_type::has_qualifiers() const
{
   return this->qualifier.flags.i != 0;
}

bool ast_type_qualifier::has_interpolation() const
{
   return this->flags.q.smooth
          || this->flags.q.flat
          || this->flags.q.noperspective;
}

bool
ast_type_qualifier::has_layout() const
{
   return this->flags.q.origin_upper_left
          || this->flags.q.pixel_center_integer
          || this->flags.q.depth_any
          || this->flags.q.depth_greater
          || this->flags.q.depth_less
          || this->flags.q.depth_unchanged
          || this->flags.q.std140
          || this->flags.q.shared
          || this->flags.q.column_major
          || this->flags.q.row_major
          || this->flags.q.packed
          || this->flags.q.explicit_location
          || this->flags.q.explicit_index
          || this->flags.q.explicit_binding
          || this->flags.q.explicit_offset;
}

bool
ast_type_qualifier::has_storage() const
{
   return this->flags.q.constant
          || this->flags.q.attribute
          || this->flags.q.varying
          || this->flags.q.in
          || this->flags.q.out
          || this->flags.q.uniform;
}

bool
ast_type_qualifier::has_auxiliary_storage() const
{
   return this->flags.q.centroid
          || this->flags.q.sample;
}

const char*
ast_type_qualifier::interpolation_string() const
{
   if (this->flags.q.smooth)
      return "smooth";
   else if (this->flags.q.flat)
      return "flat";
   else if (this->flags.q.noperspective)
      return "noperspective";
   else
      return NULL;
}

bool
ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
				    _mesa_glsl_parse_state *state,
				    ast_type_qualifier q)
{
   ast_type_qualifier ubo_mat_mask;
   ubo_mat_mask.flags.i = 0;
   ubo_mat_mask.flags.q.row_major = 1;
   ubo_mat_mask.flags.q.column_major = 1;

   ast_type_qualifier ubo_layout_mask;
   ubo_layout_mask.flags.i = 0;
   ubo_layout_mask.flags.q.std140 = 1;
   ubo_layout_mask.flags.q.packed = 1;
   ubo_layout_mask.flags.q.shared = 1;

   ast_type_qualifier ubo_binding_mask;
   ubo_binding_mask.flags.i = 0;
   ubo_binding_mask.flags.q.explicit_binding = 1;
   ubo_binding_mask.flags.q.explicit_offset = 1;

   ast_type_qualifier stream_layout_mask;
   stream_layout_mask.flags.i = 0;
   stream_layout_mask.flags.q.stream = 1;

   /* Uniform block layout qualifiers get to overwrite each
    * other (rightmost having priority), while all other
    * qualifiers currently don't allow duplicates.
    */
   ast_type_qualifier allowed_duplicates_mask;
   allowed_duplicates_mask.flags.i =
      ubo_mat_mask.flags.i |
      ubo_layout_mask.flags.i |
      ubo_binding_mask.flags.i;

   /* Geometry shaders can have several layout qualifiers
    * assigning different stream values.
    */
   if (state->stage == MESA_SHADER_GEOMETRY)
      allowed_duplicates_mask.flags.i |=
         stream_layout_mask.flags.i;

   if ((this->flags.i & q.flags.i & ~allowed_duplicates_mask.flags.i) != 0) {
      _mesa_glsl_error(loc, state,
		       "duplicate layout qualifiers used");
      return false;
   }

   if (q.flags.q.prim_type) {
      if (this->flags.q.prim_type && this->prim_type != q.prim_type) {
	 _mesa_glsl_error(loc, state,
			  "conflicting primitive type qualifiers used");
	 return false;
      }
      this->prim_type = q.prim_type;
   }

   if (q.flags.q.max_vertices) {
      if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) {
	 _mesa_glsl_error(loc, state,
			  "geometry shader set conflicting max_vertices "
			  "(%d and %d)", this->max_vertices, q.max_vertices);
	 return false;
      }
      this->max_vertices = q.max_vertices;
   }

   if (q.flags.q.invocations) {
      if (this->flags.q.invocations && this->invocations != q.invocations) {
         _mesa_glsl_error(loc, state,
                          "geometry shader set conflicting invocations "
                          "(%d and %d)", this->invocations, q.invocations);
         return false;
      }
      this->invocations = q.invocations;
   }

   if (state->stage == MESA_SHADER_GEOMETRY &&
       state->has_explicit_attrib_stream()) {
      if (q.flags.q.stream && q.stream >= state->ctx->Const.MaxVertexStreams) {
         _mesa_glsl_error(loc, state,
                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
                          "(%d > %d)",
                          q.stream, state->ctx->Const.MaxVertexStreams - 1);
      }
      if (this->flags.q.explicit_stream &&
          this->stream >= state->ctx->Const.MaxVertexStreams) {
         _mesa_glsl_error(loc, state,
                          "`stream' value is larger than MAX_VERTEX_STREAMS - 1 "
                          "(%d > %d)",
                          this->stream, state->ctx->Const.MaxVertexStreams - 1);
      }

      if (!this->flags.q.explicit_stream) {
         if (q.flags.q.stream) {
            this->flags.q.stream = 1;
            this->stream = q.stream;
         } else if (!this->flags.q.stream && this->flags.q.out) {
            /* Assign default global stream value */
            this->flags.q.stream = 1;
            this->stream = state->out_qualifier->stream;
         }
      } else {
         if (q.flags.q.explicit_stream) {
            _mesa_glsl_error(loc, state,
                             "duplicate layout `stream' qualifier");
         }
      }
   }

   if ((q.flags.i & ubo_mat_mask.flags.i) != 0)
      this->flags.i &= ~ubo_mat_mask.flags.i;
   if ((q.flags.i & ubo_layout_mask.flags.i) != 0)
      this->flags.i &= ~ubo_layout_mask.flags.i;

   for (int i = 0; i < 3; i++) {
      if (q.flags.q.local_size & (1 << i)) {
         if ((this->flags.q.local_size & (1 << i)) &&
             this->local_size[i] != q.local_size[i]) {
            _mesa_glsl_error(loc, state,
                             "compute shader set conflicting values for "
                             "local_size_%c (%d and %d)", 'x' + i,
                             this->local_size[i], q.local_size[i]);
            return false;
         }
         this->local_size[i] = q.local_size[i];
      }
   }

   this->flags.i |= q.flags.i;

   if (q.flags.q.explicit_location)
      this->location = q.location;

   if (q.flags.q.explicit_index)
      this->index = q.index;

   if (q.flags.q.explicit_binding)
      this->binding = q.binding;

   if (q.flags.q.explicit_offset)
      this->offset = q.offset;

   if (q.precision != ast_precision_none)
      this->precision = q.precision;

   if (q.flags.q.explicit_image_format) {
      this->image_format = q.image_format;
      this->image_base_type = q.image_base_type;
   }

   return true;
}

bool
ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc,
                                       _mesa_glsl_parse_state *state,
                                       ast_type_qualifier q,
                                       ast_node* &node)
{
   void *mem_ctx = state;
   bool create_gs_ast = false;
   bool create_cs_ast = false;
   ast_type_qualifier valid_in_mask;
   valid_in_mask.flags.i = 0;

   switch (state->stage) {
   case MESA_SHADER_GEOMETRY:
      if (q.flags.q.prim_type) {
         /* Make sure this is a valid input primitive type. */
         switch (q.prim_type) {
         case GL_POINTS:
         case GL_LINES:
         case GL_LINES_ADJACENCY:
         case GL_TRIANGLES:
         case GL_TRIANGLES_ADJACENCY:
            break;
         default:
            _mesa_glsl_error(loc, state,
                             "invalid geometry shader input primitive type");
            break;
         }
      }

      create_gs_ast |=
         q.flags.q.prim_type &&
         !state->in_qualifier->flags.q.prim_type;

      valid_in_mask.flags.q.prim_type = 1;
      valid_in_mask.flags.q.invocations = 1;
      break;
   case MESA_SHADER_FRAGMENT:
      if (q.flags.q.early_fragment_tests) {
         state->early_fragment_tests = true;
      } else {
         _mesa_glsl_error(loc, state, "invalid input layout qualifier");
      }
      break;
   case MESA_SHADER_COMPUTE:
      create_cs_ast |=
         q.flags.q.local_size != 0 &&
         state->in_qualifier->flags.q.local_size == 0;

      valid_in_mask.flags.q.local_size = 7;
      break;
   default:
      _mesa_glsl_error(loc, state,
                       "input layout qualifiers only valid in "
                       "geometry, fragment and compute shaders");
      break;
   }

   /* Generate an error when invalid input layout qualifiers are used. */
   if ((q.flags.i & ~valid_in_mask.flags.i) != 0) {
      _mesa_glsl_error(loc, state,
		       "invalid input layout qualifiers used");
      return false;
   }

   /* Input layout qualifiers can be specified multiple
    * times in separate declarations, as long as they match.
    */
   if (this->flags.q.prim_type) {
      if (q.flags.q.prim_type &&
          this->prim_type != q.prim_type) {
         _mesa_glsl_error(loc, state,
                          "conflicting input primitive types specified");
      }
   } else if (q.flags.q.prim_type) {
      state->in_qualifier->flags.q.prim_type = 1;
      state->in_qualifier->prim_type = q.prim_type;
   }

   if (this->flags.q.invocations &&
       q.flags.q.invocations &&
       this->invocations != q.invocations) {
      _mesa_glsl_error(loc, state,
                       "conflicting invocations counts specified");
      return false;
   } else if (q.flags.q.invocations) {
      this->flags.q.invocations = 1;
      this->invocations = q.invocations;
   }

   if (create_gs_ast) {
      node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type);
   } else if (create_cs_ast) {
      /* Infer a local_size of 1 for every unspecified dimension */
      unsigned local_size[3];
      for (int i = 0; i < 3; i++) {
         if (q.flags.q.local_size & (1 << i))
            local_size[i] = q.local_size[i];
         else
            local_size[i] = 1;
      }
      node = new(mem_ctx) ast_cs_input_layout(*loc, local_size);
   }

   return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Please refer to the file LICENSE for terms and conditions.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#pragma once

#include <functional>
#include <ros/ros.h>
#include <gps_common/GPSFix.h>
#include <eigen_conversions/eigen_msg.h>
#include "linear_algebra.hpp"
#include "debug_publisher.hpp"
#include "exception.hpp"
#include "mathematica.hpp"
#include "measurement.hpp"

namespace zubax_posekf
{
/**
 * This is the representation that can be directly used by the filter.
 */
struct GNSSLocalPosVel : public Measurement
{
    Vector3 position;
    Matrix3 position_covariance;

    Vector3 velocity;
    Matrix3 velocity_covariance;

    GNSSLocalPosVel()
    {
        position.setZero();
        position_covariance.setZero();

        velocity.setZero();
        velocity_covariance.setZero();
    }
};

/**
 * Geo coordinates expressed as longitude and latitude degrees (not radians).
 */
struct GeoLonLat
{
    Scalar lon = 0.0;
    Scalar lat = 0.0;

    GeoLonLat() { }

    GeoLonLat(Scalar arg_lon, Scalar arg_lat)
        : lon(arg_lon)
        , lat(arg_lat)
    { }
};

/**
 * This class converts between spherical geo coordinates and metric offset around certain origin.
 */
class GeoPositionConverter
{
    const Scalar MetersPerLatDegree = (110567.0 + 111699.0) * 0.5; // average from equator to poles
    const Scalar MetersPerLonDegreeOnEquator = 111321.0;

    const GeoLonLat origin_;

    Scalar latM2Deg(Scalar m) const { return m / MetersPerLatDegree; }
    Scalar latDeg2M(Scalar d) const { return d * MetersPerLatDegree; }

    Scalar lonMPerDeg(Scalar lat) const
    {
        return MetersPerLonDegreeOnEquator * ((90. - std::min(std::abs(lat), Scalar(89.999999))) / 90.);
    }

    Scalar lonM2Deg(Scalar lat, Scalar m) const { return m / lonMPerDeg(lat); }
    Scalar lonDeg2M(Scalar lat, Scalar d) const { return d * lonMPerDeg(lat); }

public:
    GeoPositionConverter(const GeoLonLat& arg_origin)
        : origin_(arg_origin)
    { }

    Vector<2> convertGeoToMetric(const GeoLonLat& geo) const
    {
        Vector<2> metric;
        metric[1] = latDeg2M(geo.lat - origin_.lat);          // lat, Y
        metric[0] = lonDeg2M(geo.lat, geo.lon - origin_.lon); // lon, X
        return metric;
    }

    GeoLonLat convertMetricToGeo(const Vector<2>& metric) const
    {
        GeoLonLat geo;
        geo.lat = latM2Deg(metric[1]) + origin_.lat;          // lat, Y
        geo.lon = lonM2Deg(geo.lat, metric[0]) + origin_.lon; // lon, X
        return geo;
    }
};

/**
 * This class obtains GNSS measurements from the specified ROS topic and converts them to proper form.
 */
class GNSSProvider
{
    const Scalar DefaultTrackStdevDeg = 30.0;
    const Scalar DefaultClimbRateStdevMS = 4.0;
    const Scalar MaxSaneSpeedMS = 515.0;        // ITAR limit, used for sanity checks
    const Scalar MinSpeedMS = 1e-3;

    ros::Subscriber sub_gnss_;
    DebugPublisher pub_debug_;

    GeoLonLat origin_;
    double origin_altitude_ = 0.0;
    bool origin_set_ = false;

    GNSSLocalPosVel last_sample_;

    struct Config
    {
        int min_sats = 0;
        int min_sats_to_init_origin = 0;
        double max_err_horz_to_init_origin = 40.0;
        double position_cov_mult = 1.0;            ///< TODO: heuristic covariance estimation
        double velocity_cov_mult = 1.0;

        Config()
        {
            ros::NodeHandle node("~gnss");

            (void)node.getParam("min_sats", min_sats);
            (void)node.getParam("min_sats_to_init_origin", min_sats_to_init_origin);
            (void)node.getParam("max_err_horz_to_init_origin", max_err_horz_to_init_origin);
            (void)node.getParam("position_cov_mult", position_cov_mult);
            (void)node.getParam("velocity_cov_mult", velocity_cov_mult);

            ROS_INFO("GNSS Provider:\n"
                     "\t~gnss/min_sats                    = %d\n"
                     "\t~gnss/min_sats_to_init_origin     = %d\n"
                    "\t~gnss/max_err_horz_to_init_origin = %f\n"
                    "\t~gnss/position_cov_mult = %f\n"
                    "\t~gnss/velocity_cov_mult = %f",
                     min_sats,
                     min_sats_to_init_origin,
                     max_err_horz_to_init_origin,
                     position_cov_mult,
                     velocity_cov_mult);
        }
    } const config_;

    std::pair<Vector3, Matrix3> computeLocalPositionWithCovariance(const gps_common::GPSFix& msg) const
    {
        enforce("GNSS origin is not set", origin_set_);

        const auto metric = GeoPositionConverter(origin_).convertGeoToMetric(GeoLonLat(msg.longitude, msg.latitude));

        Vector3 pos;
        pos[0] = metric[0];
        pos[1] = metric[1];
        pos[2] = msg.altitude - origin_altitude_;

        Matrix3 cov;
        cov.setZero();
        if (msg.position_covariance_type == msg.COVARIANCE_TYPE_UNKNOWN)
        {
            cov(0, 0) = msg.err_horz * msg.err_horz;
            cov(1, 1) = msg.err_horz * msg.err_horz;
            cov(2, 2) = msg.err_vert * msg.err_vert;
        }
        else
        {
            cov = matrixMsgToEigen<3, 3>(msg.position_covariance);
            cov = (cov + cov.transpose()) * 0.5;          // Ensure it's symmetric
        }

        enforce("GNSS position", cov.sum() > 0);

        return {pos, cov * config_.position_cov_mult};
    }

    std::pair<Vector3, Matrix3> computeVelocityVectorWithCovariance(const gps_common::GPSFix& msg) const
    {
        using namespace mathematica;

        const Scalar gnssTrack = msg.track * Degree;
        const Scalar gnssSpeed = msg.speed;
        const Scalar gnssClimb = msg.climb;

        enforce("GNSS track, speed, climb",
                (Abs(gnssTrack) <= 2.0 * Pi) &&
                (Abs(gnssSpeed) < MaxSaneSpeedMS) &&
                (Abs(gnssClimb) < MaxSaneSpeedMS));

        const auto vel = List(List(gnssSpeed * Sin(gnssTrack)),  // Lon
                              List(gnssSpeed * Cos(gnssTrack)),  // Lat
                              List(gnssClimb));                  // Climb

        const Scalar err_track_rad = ((msg.err_track > 0) ? msg.err_track : DefaultTrackStdevDeg) * Degree;

        const auto Rpolar = List(List(Power(err_track_rad, 2), 0, 0),  // stdev --> covariance matrix
                                 List(0, Power(msg.err_speed, 2), 0),
                                 List(0, 0, Power((msg.err_climb > 0) ? msg.err_climb : DefaultClimbRateStdevMS, 2)));

        if ((Rpolar(0, 0) <= 0) || (Rpolar(1, 1) <= 0) || (Rpolar(2, 2) <= 0))
        {
            std::ostringstream os;
            os << "GNSS R polar:\n" << Rpolar;
            throw Exception(os.str());
        }

        // Convariance transformation Jacobian
        Matrix3 Gpolar;
        {
            /*
             * Special case: if speed ~= track ~= 0, the Jacobian produces zero variance for the longitudinal speed:
             *  0  0   0
             *  0 svar 0
             *  0  0  cvar
             * Zero variances aren't allowed by the filter.
             */
            const Scalar speed = (gnssSpeed > MinSpeedMS) ? gnssSpeed : MinSpeedMS; // Work around
            Gpolar = List(List(  speed * Cos(gnssTrack),  Sin(gnssTrack), 0),
                          List(-(speed * Sin(gnssTrack)), Cos(gnssTrack), 0),
                          List(0,                         0,              1));
        }

        const Matrix3 R = Gpolar * Rpolar * Gpolar.transpose();

        if ((R(0, 0) <= 0) || (R(1, 1) <= 0) || (R(2, 2) <= 0) || !std::isfinite(R.sum()))
        {
            std::ostringstream os;
            os << "GNSS R vel:\n" << R << "\nGNSS R polar:\n" << Rpolar << "\nGNSS G polar:\n" << Gpolar
                << "\ntrack=" << gnssTrack << "\nspeed=" << gnssSpeed;
            throw Exception(os.str());
        }

        return {vel, R * config_.velocity_cov_mult};
    }

    void cbGnss(const gps_common::GPSFix& msg)
    {
        /*
         * Drop invalid messages
         */
        {
            const bool has_fix = msg.status.status >= msg.status.STATUS_FIX;
            const bool sats_ok = msg.status.satellites_used >= config_.min_sats;
            if (!has_fix || !sats_ok)
            {
                ROS_DEBUG("GNSS Provider: Message dropped: status=%d, nsats=%d",
                          msg.status.status, msg.status.satellites_used);
                return;
            }
        }

        /*
         * Initialize origin if necessary
         */
        if (!origin_set_)
        {
            if (msg.status.satellites_used >= config_.min_sats_to_init_origin &&
                msg.err_horz < config_.max_err_horz_to_init_origin &&
                msg.status.status >= msg.status.STATUS_FIX)
            {
                origin_.lon = msg.longitude;
                origin_.lat = msg.latitude;
                origin_altitude_ = msg.altitude;
                origin_set_ = true;
                ROS_INFO("GNSS Provider: Origin at lon=%f, lat=%f, alt=%f",
                         origin_.lon, origin_.lat, origin_altitude_);
            }
            else
            {
                ROS_INFO_THROTTLE(1, "GNSS Provider: Can't initialize origin: nsats=%d, err_horz=%f, status=%d",
                                  msg.status.satellites_used, msg.err_horz, static_cast<int>(msg.status.status));
                return;
            }
        }

        /*
         * Position and covariance
         */
        const auto pos_and_cov = computeLocalPositionWithCovariance(msg);
        pub_debug_.publish("gnss_pos", pos_and_cov.first);
        pub_debug_.publish("gnss_pos_cov", pos_and_cov.second);

        /*
         * Velocity and covariance
         */
        const auto vel_and_cov = computeVelocityVectorWithCovariance(msg);
        pub_debug_.publish("gnss_vel", vel_and_cov.first);
        pub_debug_.publish("gnss_vel_cov", vel_and_cov.second);

        /*
         * Output
         */
        last_sample_.timestamp = msg.header.stamp;

        last_sample_.velocity = vel_and_cov.first;
        last_sample_.velocity_covariance = vel_and_cov.second;

        last_sample_.position = pos_and_cov.first;
        last_sample_.position_covariance = pos_and_cov.second;

        ROS_ASSERT(origin_set_);
        if (on_sample)
        {
            on_sample(last_sample_, msg);
        }
    }

public:
    GNSSProvider(ros::NodeHandle& node, const std::string topic)
    {
        sub_gnss_ = node.subscribe(topic, 10, &GNSSProvider::cbGnss, this);
    }

    GNSSLocalPosVel getLastSample() const { return last_sample_; }

    std::function<void (const GNSSLocalPosVel&, const gps_common::GPSFix&)> on_sample;
};

}
<commit_msg>Fixed GNSS offset computation<commit_after>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Please refer to the file LICENSE for terms and conditions.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#pragma once

#include <functional>
#include <ros/ros.h>
#include <gps_common/GPSFix.h>
#include <eigen_conversions/eigen_msg.h>
#include "linear_algebra.hpp"
#include "debug_publisher.hpp"
#include "exception.hpp"
#include "mathematica.hpp"
#include "measurement.hpp"

namespace zubax_posekf
{
/**
 * This is the representation that can be directly used by the filter.
 */
struct GNSSLocalPosVel : public Measurement
{
    Vector3 position;
    Matrix3 position_covariance;

    Vector3 velocity;
    Matrix3 velocity_covariance;

    GNSSLocalPosVel()
    {
        position.setZero();
        position_covariance.setZero();

        velocity.setZero();
        velocity_covariance.setZero();
    }
};

/**
 * Geo coordinates expressed as longitude and latitude degrees (not radians).
 */
struct GeoLonLat
{
    Scalar lon = 0.0;
    Scalar lat = 0.0;

    GeoLonLat() { }

    GeoLonLat(Scalar arg_lon, Scalar arg_lat)
        : lon(arg_lon)
        , lat(arg_lat)
    { }
};

/**
 * This class converts between spherical geo coordinates and metric offset around certain origin.
 */
class GeoPositionConverter
{
    static constexpr Scalar EarthRadiusMeters = 6372797.0;

    const GeoLonLat origin_;

    Scalar greatCircleToMetric(Scalar angle) const
    {
        // m = (earth_perimeter / 2PI) * angle
        // m = ((2PI * earth_radius) / 2PI) * angle
        // m = earth_radius * angle
        return EarthRadiusMeters * angle;
    }

    Scalar greatCircleAngle(const Vector3& a, const Vector3& b) const
    {
        using namespace std;
        Scalar lat1, lon1, lat2, lon2;
        decomposeLatLon(a, b, lat1, lon1, lat2, lon2);
        Scalar t1 = sin((lat2-lat1) / 2.0);
        t1 *= t1;
        Scalar t2 = sin((lon2-lon1) / 2.0);
        t2 *= t2;
        return 2.0 * asin(sqrt(t1 + cos(lat1) * cos(lat2) * t2));
    }

    void decomposeLatLon(const Vector3& a, Scalar& lat1, Scalar& lon1) const
    {
        static const Scalar deg2rad = M_PI / 180.0;
        lat1 = a.y() * deg2rad;
        lon1 = a.x() * deg2rad;
    }

    void decomposeLatLon(const Vector3& a, const Vector3& b,
                         Scalar& lat1, Scalar& lon1, Scalar& lat2, Scalar& lon2) const
    {
        decomposeLatLon(a, lat1, lon1);
        decomposeLatLon(b, lat2, lon2);
    }

    Scalar genericDistance(const Vector3& a, const Vector3& b, bool plane) const
    {
        const Scalar Precision = 1e-9;

        Scalar d_xy = 0.0;

        if ((std::abs(a.x() - b.x()) > Precision) ||
            (std::abs(a.y() - b.y()) > Precision))
        {
            const Scalar gca = greatCircleAngle(a, b);
            d_xy = greatCircleToMetric(gca);
        }

        if (plane)
        {
            return d_xy;
        }
        else
        {
            const Scalar d_z = a.z() - b.z();
            return std::sqrt(d_xy * d_xy + d_z * d_z);
        }
    }

public:
    GeoPositionConverter(const GeoLonLat& arg_origin)
        : origin_(arg_origin)
    { }

    Vector<2> convertGeoToMetric(const GeoLonLat& geo) const
    {
        const Vector3 origin_vector(origin_.lon, origin_.lat, 0.0);

        Scalar x = genericDistance(origin_vector, Vector3(geo.lon, origin_.lat, 0.0), true);
        if (geo.lon < origin_.lon)
        {
            x *= -1.0;
        }

        Scalar y = genericDistance(origin_vector, Vector3(origin_.lon, geo.lat, 0.0), true);
        if (geo.lat < origin_.lat)
        {
            y *= -1.0;
        }

        return Vector<2>(x, y);
    }
};

/**
 * This class obtains GNSS measurements from the specified ROS topic and converts them to proper form.
 */
class GNSSProvider
{
    const Scalar DefaultTrackStdevDeg = 30.0;
    const Scalar DefaultClimbRateStdevMS = 4.0;
    const Scalar MaxSaneSpeedMS = 515.0;        // ITAR limit, used for sanity checks
    const Scalar MinSpeedMS = 1e-3;

    ros::Subscriber sub_gnss_;
    DebugPublisher pub_debug_;

    GeoLonLat origin_;
    Scalar origin_altitude_ = 0.0;
    bool origin_set_ = false;

    GNSSLocalPosVel last_sample_;

    struct Config
    {
        int min_sats = 0;
        int min_sats_to_init_origin = 0;
        double max_err_horz_to_init_origin = 40.0;
        double position_cov_mult = 1.0;            ///< TODO: heuristic covariance estimation
        double velocity_cov_mult = 1.0;

        Config()
        {
            ros::NodeHandle node("~gnss");

            (void)node.getParam("min_sats", min_sats);
            (void)node.getParam("min_sats_to_init_origin", min_sats_to_init_origin);
            (void)node.getParam("max_err_horz_to_init_origin", max_err_horz_to_init_origin);
            (void)node.getParam("position_cov_mult", position_cov_mult);
            (void)node.getParam("velocity_cov_mult", velocity_cov_mult);

            ROS_INFO("GNSS Provider:\n"
                     "\t~gnss/min_sats                    = %d\n"
                     "\t~gnss/min_sats_to_init_origin     = %d\n"
                    "\t~gnss/max_err_horz_to_init_origin = %f\n"
                    "\t~gnss/position_cov_mult = %f\n"
                    "\t~gnss/velocity_cov_mult = %f",
                     min_sats,
                     min_sats_to_init_origin,
                     max_err_horz_to_init_origin,
                     position_cov_mult,
                     velocity_cov_mult);
        }
    } const config_;

    std::pair<Vector3, Matrix3> computeLocalPositionWithCovariance(const gps_common::GPSFix& msg) const
    {
        enforce("GNSS origin is not set", origin_set_);

        const auto metric = GeoPositionConverter(origin_).convertGeoToMetric(GeoLonLat(msg.longitude, msg.latitude));

        Vector3 pos;
        pos[0] = metric[0];
        pos[1] = metric[1];
        pos[2] = msg.altitude - origin_altitude_;

        Matrix3 cov;
        cov.setZero();
        if (msg.position_covariance_type == msg.COVARIANCE_TYPE_UNKNOWN)
        {
            cov(0, 0) = msg.err_horz * msg.err_horz;
            cov(1, 1) = msg.err_horz * msg.err_horz;
            cov(2, 2) = msg.err_vert * msg.err_vert;
        }
        else
        {
            cov = matrixMsgToEigen<3, 3>(msg.position_covariance);
            cov = (cov + cov.transpose()) * 0.5;          // Ensure it's symmetric
        }

        enforce("GNSS position", cov.sum() > 0);

        return {pos, cov * config_.position_cov_mult};
    }

    std::pair<Vector3, Matrix3> computeVelocityVectorWithCovariance(const gps_common::GPSFix& msg) const
    {
        using namespace mathematica;

        const Scalar gnssTrack = msg.track * Degree;
        const Scalar gnssSpeed = msg.speed;
        const Scalar gnssClimb = msg.climb;

        enforce("GNSS track, speed, climb",
                (Abs(gnssTrack) <= 2.0 * Pi) &&
                (Abs(gnssSpeed) < MaxSaneSpeedMS) &&
                (Abs(gnssClimb) < MaxSaneSpeedMS));

        const auto vel = List(List(gnssSpeed * Sin(gnssTrack)),  // Lon
                              List(gnssSpeed * Cos(gnssTrack)),  // Lat
                              List(gnssClimb));                  // Climb

        const Scalar err_track_rad = ((msg.err_track > 0) ? msg.err_track : DefaultTrackStdevDeg) * Degree;

        const auto Rpolar = List(List(Power(err_track_rad, 2), 0, 0),  // stdev --> covariance matrix
                                 List(0, Power(msg.err_speed, 2), 0),
                                 List(0, 0, Power((msg.err_climb > 0) ? msg.err_climb : DefaultClimbRateStdevMS, 2)));

        if ((Rpolar(0, 0) <= 0) || (Rpolar(1, 1) <= 0) || (Rpolar(2, 2) <= 0))
        {
            std::ostringstream os;
            os << "GNSS R polar:\n" << Rpolar;
            throw Exception(os.str());
        }

        // Convariance transformation Jacobian
        Matrix3 Gpolar;
        {
            /*
             * Special case: if speed ~= track ~= 0, the Jacobian produces zero variance for the longitudinal speed:
             *  0  0   0
             *  0 svar 0
             *  0  0  cvar
             * Zero variances aren't allowed by the filter.
             */
            const Scalar speed = (gnssSpeed > MinSpeedMS) ? gnssSpeed : MinSpeedMS; // Work around
            Gpolar = List(List(  speed * Cos(gnssTrack),  Sin(gnssTrack), 0),
                          List(-(speed * Sin(gnssTrack)), Cos(gnssTrack), 0),
                          List(0,                         0,              1));
        }

        const Matrix3 R = Gpolar * Rpolar * Gpolar.transpose();

        if ((R(0, 0) <= 0) || (R(1, 1) <= 0) || (R(2, 2) <= 0) || !std::isfinite(R.sum()))
        {
            std::ostringstream os;
            os << "GNSS R vel:\n" << R << "\nGNSS R polar:\n" << Rpolar << "\nGNSS G polar:\n" << Gpolar
                << "\ntrack=" << gnssTrack << "\nspeed=" << gnssSpeed;
            throw Exception(os.str());
        }

        return {vel, R * config_.velocity_cov_mult};
    }

    void cbGnss(const gps_common::GPSFix& msg)
    {
        /*
         * Drop invalid messages
         */
        {
            const bool has_fix = msg.status.status >= msg.status.STATUS_FIX;
            const bool sats_ok = msg.status.satellites_used >= config_.min_sats;
            if (!has_fix || !sats_ok)
            {
                ROS_DEBUG("GNSS Provider: Message dropped: status=%d, nsats=%d",
                          msg.status.status, msg.status.satellites_used);
                return;
            }
        }

        /*
         * Initialize origin if necessary
         */
        if (!origin_set_)
        {
            if (msg.status.satellites_used >= config_.min_sats_to_init_origin &&
                msg.err_horz < config_.max_err_horz_to_init_origin &&
                msg.status.status >= msg.status.STATUS_FIX)
            {
                origin_.lon = msg.longitude;
                origin_.lat = msg.latitude;
                origin_altitude_ = msg.altitude;
                origin_set_ = true;
                ROS_INFO("GNSS Provider: Origin at lon=%f, lat=%f, alt=%f",
                         origin_.lon, origin_.lat, origin_altitude_);
            }
            else
            {
                ROS_INFO_THROTTLE(1, "GNSS Provider: Can't initialize origin: nsats=%d, err_horz=%f, status=%d",
                                  msg.status.satellites_used, msg.err_horz, static_cast<int>(msg.status.status));
                return;
            }
        }

        /*
         * Position and covariance
         */
        const auto pos_and_cov = computeLocalPositionWithCovariance(msg);
        pub_debug_.publish("gnss_pos", pos_and_cov.first);
        pub_debug_.publish("gnss_pos_cov", pos_and_cov.second);

        /*
         * Velocity and covariance
         */
        const auto vel_and_cov = computeVelocityVectorWithCovariance(msg);
        pub_debug_.publish("gnss_vel", vel_and_cov.first);
        pub_debug_.publish("gnss_vel_cov", vel_and_cov.second);

        /*
         * Output
         */
        last_sample_.timestamp = msg.header.stamp;

        last_sample_.velocity = vel_and_cov.first;
        last_sample_.velocity_covariance = vel_and_cov.second;

        last_sample_.position = pos_and_cov.first;
        last_sample_.position_covariance = pos_and_cov.second;

        ROS_ASSERT(origin_set_);
        if (on_sample)
        {
            on_sample(last_sample_, msg);
        }
    }

public:
    GNSSProvider(ros::NodeHandle& node, const std::string topic)
    {
        sub_gnss_ = node.subscribe(topic, 10, &GNSSProvider::cbGnss, this);
    }

    GNSSLocalPosVel getLastSample() const { return last_sample_; }

    std::function<void (const GNSSLocalPosVel&, const gps_common::GPSFix&)> on_sample;
};

}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrTypes.h"
#include "SkThread.h"       // for sk_atomic_inc

// Well, the dummy_ "fix" caused a warning on windows, so hiding all of it
// until we can find a universal fix.
#if 0
// This used to be a global scope, but we got a warning about unused variable
// so we moved it into here. We just want it to compile, so we can test the
// static asserts.
static inline void dummy_function_to_avoid_unused_var_warning() {
    GrCacheID::Key kAssertKey;
    GR_STATIC_ASSERT(sizeof(kAssertKey.fData8) == sizeof(kAssertKey.fData32));
    GR_STATIC_ASSERT(sizeof(kAssertKey.fData8) == sizeof(kAssertKey.fData64));
    GR_STATIC_ASSERT(sizeof(kAssertKey.fData8) == sizeof(kAssertKey));
}
#endif

GrCacheID::Domain GrCacheID::GenerateDomain() {
    static int32_t gNextDomain = kInvalid_Domain + 1;

    int32_t domain = sk_atomic_inc(&gNextDomain);
    if (domain >= 1 << (8 * sizeof(Domain))) {
        GrCrash("Too many Cache Domains");
    }

    return static_cast<Domain>(domain);
}
<commit_msg>Re-enable static asserts with windows warning fix.<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrTypes.h"
#include "SkThread.h"       // for sk_atomic_inc

// This used to be a global scope, but we got a warning about unused variable
// so we moved it into here. We just want it to compile, so we can test the
// static asserts.
static inline void dummy_function_to_avoid_unused_var_warning() {
    static const GrCacheID::Key kAssertKey;
    GR_STATIC_ASSERT(sizeof(kAssertKey.fData8) == sizeof(kAssertKey.fData32));
    GR_STATIC_ASSERT(sizeof(kAssertKey.fData8) == sizeof(kAssertKey.fData64));
    GR_STATIC_ASSERT(sizeof(kAssertKey.fData8) == sizeof(kAssertKey));
}

GrCacheID::Domain GrCacheID::GenerateDomain() {
    static int32_t gNextDomain = kInvalid_Domain + 1;

    int32_t domain = sk_atomic_inc(&gNextDomain);
    if (domain >= 1 << (8 * sizeof(Domain))) {
        GrCrash("Too many Cache Domains");
    }

    return static_cast<Domain>(domain);
}
<|endoftext|>


<commit_before>/*
 * Retina.h
 *
 *  Created on: Jul 29, 2008
 *
 */

#ifndef RETINA_HPP_
#define RETINA_HPP_

#include "HyPerLayer.hpp"
#include "../kernels/Retina_params.h"
#include "../arch/opencl/pv_opencl.h"
#include "../arch/opencl/pv_uint4.h"
#include "Image.hpp"

#define NUM_RETINA_CHANNELS 2
#define NUM_RETINA_EVENTS   3
#define EV_R_PHI_E    0
#define EV_R_PHI_I    1
#define EV_R_ACTIVITY 2

namespace PV
{

class Retina: public PV::HyPerLayer
{
public:

   friend int test_kernels(int argc, char * argv[]);

   Retina(const char * name, HyPerCol * hc);
   virtual ~Retina();

   int initialize(PVLayerType type);
   int setParams(PVParams * p);

   virtual int triggerReceive(InterColComm* comm);
   virtual int updateState(float time, float dt);
   virtual int updateStateOpenCL(float time, float dt);
   virtual int waitOnPublish(InterColComm* comm);
   virtual int writeState(float time);

protected:

#ifdef PV_USE_OPENCL
   virtual int initializeThreadBuffers();
   virtual int initializeThreadKernels();

   CLBuffer * clRand;
#endif

   bool spikingFlag;        // specifies that layer is spiking
   Retina_params rParams;   // used in update state
   uint4 * rand_state;      // state for random numbers

private:

   // For input from a given source input layer, determine which
   // cells in this layer will respond to the input activity.
   // Return the feature vectors for both the input and the sensitive
   // neurons, since most likely we will have to determine those.
   int findPostSynaptic(int dim, int maxSize, int col,
      // input: which layer, which neuron
      HyPerLayer *lSource, float pos[],
      // output: how many of our neurons are connected.
      // an array with their indices.
      // an array with their feature vectors.
      int * nNeurons, int nConnectedNeurons[], float * vPos);

   int calculateWeights(HyPerLayer * lSource, float * pos, float * vPos, float * vfWeights );

};

} // namespace PV

#endif /* RETINA_HPP_ */
<commit_msg>Added background activity to border regions.<commit_after>/*
 * Retina.h
 *
 *  Created on: Jul 29, 2008
 *
 */

#ifndef RETINA_HPP_
#define RETINA_HPP_

#include "HyPerLayer.hpp"
#include "../kernels/Retina_params.h"
#include "../arch/opencl/pv_opencl.h"
#include "../arch/opencl/pv_uint4.h"
#include "Image.hpp"

#define NUM_RETINA_CHANNELS 2
#define NUM_RETINA_EVENTS   3
#define EV_R_PHI_E    0
#define EV_R_PHI_I    1
#define EV_R_ACTIVITY 2

namespace PV
{

class Retina: public PV::HyPerLayer
{
public:

   friend int test_kernels(int argc, char * argv[]);

   Retina(const char * name, HyPerCol * hc);
   virtual ~Retina();

   int initialize(PVLayerType type);
   int setParams(PVParams * p);

   virtual int triggerReceive(InterColComm* comm);
   virtual int updateState(float time, float dt);
   virtual int updateStateOpenCL(float time, float dt);
   virtual int updateBorder(float time, float dt);
   virtual int waitOnPublish(InterColComm* comm);
   virtual int writeState(float time);

protected:

#ifdef PV_USE_OPENCL
   virtual int initializeThreadBuffers();
   virtual int initializeThreadKernels();

   CLBuffer * clRand;
#endif

   bool spikingFlag;        // specifies that layer is spiking
   Retina_params rParams;   // used in update state
   uint4 * rand_state;      // state for random numbers

private:

   // For input from a given source input layer, determine which
   // cells in this layer will respond to the input activity.
   // Return the feature vectors for both the input and the sensitive
   // neurons, since most likely we will have to determine those.
   int findPostSynaptic(int dim, int maxSize, int col,
      // input: which layer, which neuron
      HyPerLayer *lSource, float pos[],
      // output: how many of our neurons are connected.
      // an array with their indices.
      // an array with their feature vectors.
      int * nNeurons, int nConnectedNeurons[], float * vPos);

   int calculateWeights(HyPerLayer * lSource, float * pos, float * vPos, float * vfWeights );

};

} // namespace PV

#endif /* RETINA_HPP_ */
<|endoftext|>


<commit_before>#include "globals.hh"
#include "shared.hh"
#include "store-api.hh"
#include "util.hh"

#include <algorithm>
#include <cctype>
#include <exception>
#include <iostream>
#include <mutex>

#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

#include <openssl/crypto.h>

namespace nix {

static bool gcWarning = true;

void printGCWarning()
{
    if (!gcWarning) return;
    static bool haveWarned = false;
    warnOnce(haveWarned,
        "you did not specify '--add-root'; "
        "the result might be removed by the garbage collector");
}

void printMissing(ref<Store> store, const PathSet & paths, Verbosity lvl)
{
    unsigned long long downloadSize, narSize;
    PathSet willBuild, willSubstitute, unknown;
    store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
    printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
}

void printMissing(ref<Store> store, const PathSet & willBuild,
    const PathSet & willSubstitute, const PathSet & unknown,
    unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl)
{
    if (!willBuild.empty()) {
        printMsg(lvl, "these derivations will be built:");
        Paths sorted = store->topoSortPaths(willBuild);
        reverse(sorted.begin(), sorted.end());
        for (auto & i : sorted)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!willSubstitute.empty()) {
        printMsg(lvl, fmt("these paths will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                downloadSize / (1024.0 * 1024.0),
                narSize / (1024.0 * 1024.0)));
        for (auto & i : willSubstitute)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!unknown.empty()) {
        printMsg(lvl, fmt("don't know how to build these paths%s:",
                (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")));
        for (auto & i : unknown)
            printMsg(lvl, fmt("  %s", i));
    }
}

string getArg(const string & opt,
    Strings::iterator & i, const Strings::iterator & end)
{
    ++i;
    if (i == end) throw UsageError(format("'%1%' requires an argument") % opt);
    return *i;
}

/* OpenSSL is not thread-safe by default - it will randomly crash
   unless the user supplies a mutex locking function. So let's do
   that. */
static std::vector<std::mutex> opensslLocks;

static void opensslLockCallback(int mode, int type, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        opensslLocks[type].lock();
    else
        opensslLocks[type].unlock();
}

static void sigHandler(int signo) { }

void initNix()
{
    /* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF
    static char buf[1024];
    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
#endif

    /* Initialise OpenSSL locking. */
    opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
    CRYPTO_set_locking_callback(opensslLockCallback);

    settings.loadConfFile();

    startSignalHandlerThread();

    /* Reset SIGCHLD to its default. */
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_handler = SIG_DFL;
    act.sa_flags = 0;
    if (sigaction(SIGCHLD, &act, 0))
        throw SysError("resetting SIGCHLD");

    /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */
    act.sa_handler = sigHandler;
    if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");

    /* Register a SIGSEGV handler to detect stack overflows. */
    detectStackOverflow();

    /* There is no privacy in the Nix system ;-)  At least not for
       now.  In particular, store objects should be readable by
       everybody. */
    umask(0022);

    /* Initialise the PRNG. */
    struct timeval tv;
    gettimeofday(&tv, 0);
    srandom(tv.tv_usec);

    /* On macOS, don't use the per-session TMPDIR (as set e.g. by
       sshd). This breaks build users because they don't have access
       to the TMPDIR, in particular in ‘nix-store --serve’. */
#if __APPLE__
    if (getuid() == 0 && hasPrefix(getEnv("TMPDIR"), "/var/folders/"))
        unsetenv("TMPDIR");
#endif
}

LegacyArgs::LegacyArgs(const std::string & programName,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
    : MixCommonArgs(programName), parseArg(parseArg)
{
    mkFlag()
        .longName("no-build-output")
        .shortName('Q')
        .description("do not show build output")
        .set(&settings.verboseBuild, false);

    mkFlag()
        .longName("keep-failed")
        .shortName('K')
        .description("keep temporary directories of failed builds")
        .set(&(bool&) settings.keepFailed, true);

    mkFlag()
        .longName("keep-going")
        .shortName('k')
        .description("keep going after a build fails")
        .set(&(bool&) settings.keepGoing, true);

    mkFlag()
        .longName("fallback")
        .description("build from source if substitution fails")
        .set(&(bool&) settings.tryFallback, true);

    mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) {
        settings.set("max-jobs", s);
    });

    auto intSettingAlias = [&](char shortName, const std::string & longName,
        const std::string & description, const std::string & dest) {
        mkFlag<unsigned int>(shortName, longName, description, [=](unsigned int n) {
            settings.set(dest, std::to_string(n));
        });
    };

    intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores");
    intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time");
    intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout");

    mkFlag(0, "readonly-mode", "do not write to the Nix store",
        &settings.readOnlyMode);

    mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors",
        &settings.showTrace);

    mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
        &gcWarning, false);
}

bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
{
    if (MixCommonArgs::processFlag(pos, end)) return true;
    bool res = parseArg(pos, end);
    if (res) ++pos;
    return res;
}

bool LegacyArgs::processArgs(const Strings & args, bool finish)
{
    if (args.empty()) return true;
    assert(args.size() == 1);
    Strings ss(args);
    auto pos = ss.begin();
    if (!parseArg(pos, ss.end()))
        throw UsageError(format("unexpected argument '%1%'") % args.front());
    return true;
}

void parseCmdLine(int argc, char * * argv,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    parseCmdLine(baseNameOf(argv[0]), argvToStrings(argc, argv), parseArg);
}

void parseCmdLine(const string & programName, const Strings & args,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    LegacyArgs(programName, parseArg).parseCmdline(args);
}

void printVersion(const string & programName)
{
    std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
    if (verbosity > lvlInfo) {
        Strings cfg;
#if HAVE_BOEHMGC
        cfg.push_back("gc");
#endif
#if HAVE_SODIUM
        cfg.push_back("signed-caches");
#endif
        std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
        std::cout << "Configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
        std::cout << "Store directory: " << settings.nixStore << "\n";
        std::cout << "State directory: " << settings.nixStateDir << "\n";
    }
    throw Exit();
}

void showManPage(const string & name)
{
    restoreSignals();
    execlp("man", "man", name.c_str(), NULL);
    throw SysError(format("command 'man %1%' failed") % name.c_str());
}

int handleExceptions(const string & programName, std::function<void()> fun)
{
    ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this

    string error = ANSI_RED "error:" ANSI_NORMAL " ";
    try {
        try {
            fun();
        } catch (...) {
            /* Subtle: we have to make sure that any `interrupted'
               condition is discharged before we reach printMsg()
               below, since otherwise it will throw an (uncaught)
               exception. */
            setInterruptThrown();
            throw;
        }
    } catch (Exit & e) {
        return e.status;
    } catch (UsageError & e) {
        printError(
            format(error + "%1%\nTry '%2% --help' for more information.")
            % e.what() % programName);
        return 1;
    } catch (BaseError & e) {
        printError(format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
        if (e.prefix() != "" && !settings.showTrace)
            printError("(use '--show-trace' to show detailed location information)");
        return e.status;
    } catch (std::bad_alloc & e) {
        printError(error + "out of memory");
        return 1;
    } catch (std::exception & e) {
        printError(error + e.what());
        return 1;
    }

    return 0;
}

RunPager::RunPager()
{
    if (!isatty(STDOUT_FILENO)) return;
    char * pager = getenv("NIX_PAGER");
    if (!pager) pager = getenv("PAGER");
    if (pager && ((string) pager == "" || (string) pager == "cat")) return;

    Pipe toPager;
    toPager.create();

    pid = startProcess([&]() {
        if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("dupping stdin");
        if (!getenv("LESS"))
            setenv("LESS", "FRSXMK", 1);
        restoreSignals();
        if (pager)
            execl("/bin/sh", "sh", "-c", pager, NULL);
        execlp("pager", "pager", NULL);
        execlp("less", "less", NULL);
        execlp("more", "more", NULL);
        throw SysError(format("executing '%1%'") % pager);
    });

    pid.setKillSignal(SIGINT);

    if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
        throw SysError("dupping stdout");
}

RunPager::~RunPager()
{
    try {
        if (pid != -1) {
            std::cout.flush();
            close(STDOUT_FILENO);
            pid.wait();
        }
    } catch (...) {
        ignoreException();
    }
}

string showBytes(unsigned long long bytes)
{
    return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}

PrintFreed::~PrintFreed()
{
    if (show)
        std::cout << format("%1% store paths deleted, %2% freed\n")
            % results.paths.size()
            % showBytes(results.bytesFreed);
}

}
<commit_msg>Add --store argument to legacy commands<commit_after>#include "globals.hh"
#include "shared.hh"
#include "store-api.hh"
#include "util.hh"

#include <algorithm>
#include <cctype>
#include <exception>
#include <iostream>
#include <mutex>

#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

#include <openssl/crypto.h>

namespace nix {

static bool gcWarning = true;

void printGCWarning()
{
    if (!gcWarning) return;
    static bool haveWarned = false;
    warnOnce(haveWarned,
        "you did not specify '--add-root'; "
        "the result might be removed by the garbage collector");
}

void printMissing(ref<Store> store, const PathSet & paths, Verbosity lvl)
{
    unsigned long long downloadSize, narSize;
    PathSet willBuild, willSubstitute, unknown;
    store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
    printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
}

void printMissing(ref<Store> store, const PathSet & willBuild,
    const PathSet & willSubstitute, const PathSet & unknown,
    unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl)
{
    if (!willBuild.empty()) {
        printMsg(lvl, "these derivations will be built:");
        Paths sorted = store->topoSortPaths(willBuild);
        reverse(sorted.begin(), sorted.end());
        for (auto & i : sorted)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!willSubstitute.empty()) {
        printMsg(lvl, fmt("these paths will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                downloadSize / (1024.0 * 1024.0),
                narSize / (1024.0 * 1024.0)));
        for (auto & i : willSubstitute)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!unknown.empty()) {
        printMsg(lvl, fmt("don't know how to build these paths%s:",
                (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")));
        for (auto & i : unknown)
            printMsg(lvl, fmt("  %s", i));
    }
}

string getArg(const string & opt,
    Strings::iterator & i, const Strings::iterator & end)
{
    ++i;
    if (i == end) throw UsageError(format("'%1%' requires an argument") % opt);
    return *i;
}

/* OpenSSL is not thread-safe by default - it will randomly crash
   unless the user supplies a mutex locking function. So let's do
   that. */
static std::vector<std::mutex> opensslLocks;

static void opensslLockCallback(int mode, int type, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        opensslLocks[type].lock();
    else
        opensslLocks[type].unlock();
}

static void sigHandler(int signo) { }

void initNix()
{
    /* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF
    static char buf[1024];
    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
#endif

    /* Initialise OpenSSL locking. */
    opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
    CRYPTO_set_locking_callback(opensslLockCallback);

    settings.loadConfFile();

    startSignalHandlerThread();

    /* Reset SIGCHLD to its default. */
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_handler = SIG_DFL;
    act.sa_flags = 0;
    if (sigaction(SIGCHLD, &act, 0))
        throw SysError("resetting SIGCHLD");

    /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */
    act.sa_handler = sigHandler;
    if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");

    /* Register a SIGSEGV handler to detect stack overflows. */
    detectStackOverflow();

    /* There is no privacy in the Nix system ;-)  At least not for
       now.  In particular, store objects should be readable by
       everybody. */
    umask(0022);

    /* Initialise the PRNG. */
    struct timeval tv;
    gettimeofday(&tv, 0);
    srandom(tv.tv_usec);

    /* On macOS, don't use the per-session TMPDIR (as set e.g. by
       sshd). This breaks build users because they don't have access
       to the TMPDIR, in particular in ‘nix-store --serve’. */
#if __APPLE__
    if (getuid() == 0 && hasPrefix(getEnv("TMPDIR"), "/var/folders/"))
        unsetenv("TMPDIR");
#endif
}

LegacyArgs::LegacyArgs(const std::string & programName,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
    : MixCommonArgs(programName), parseArg(parseArg)
{
    mkFlag()
        .longName("no-build-output")
        .shortName('Q')
        .description("do not show build output")
        .set(&settings.verboseBuild, false);

    mkFlag()
        .longName("keep-failed")
        .shortName('K')
        .description("keep temporary directories of failed builds")
        .set(&(bool&) settings.keepFailed, true);

    mkFlag()
        .longName("keep-going")
        .shortName('k')
        .description("keep going after a build fails")
        .set(&(bool&) settings.keepGoing, true);

    mkFlag()
        .longName("fallback")
        .description("build from source if substitution fails")
        .set(&(bool&) settings.tryFallback, true);

    mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) {
        settings.set("max-jobs", s);
    });

    auto intSettingAlias = [&](char shortName, const std::string & longName,
        const std::string & description, const std::string & dest) {
        mkFlag<unsigned int>(shortName, longName, description, [=](unsigned int n) {
            settings.set(dest, std::to_string(n));
        });
    };

    intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores");
    intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time");
    intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout");

    mkFlag(0, "readonly-mode", "do not write to the Nix store",
        &settings.readOnlyMode);

    mkFlag(0, "show-trace", "show Nix expression stack trace in evaluation errors",
        &settings.showTrace);

    mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
        &gcWarning, false);

    mkFlag()
        .longName("store")
        .label("store-uri")
        .description("URI of the Nix store to use")
        .dest(&(std::string&) settings.storeUri);
}

bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
{
    if (MixCommonArgs::processFlag(pos, end)) return true;
    bool res = parseArg(pos, end);
    if (res) ++pos;
    return res;
}

bool LegacyArgs::processArgs(const Strings & args, bool finish)
{
    if (args.empty()) return true;
    assert(args.size() == 1);
    Strings ss(args);
    auto pos = ss.begin();
    if (!parseArg(pos, ss.end()))
        throw UsageError(format("unexpected argument '%1%'") % args.front());
    return true;
}

void parseCmdLine(int argc, char * * argv,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    parseCmdLine(baseNameOf(argv[0]), argvToStrings(argc, argv), parseArg);
}

void parseCmdLine(const string & programName, const Strings & args,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    LegacyArgs(programName, parseArg).parseCmdline(args);
}

void printVersion(const string & programName)
{
    std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
    if (verbosity > lvlInfo) {
        Strings cfg;
#if HAVE_BOEHMGC
        cfg.push_back("gc");
#endif
#if HAVE_SODIUM
        cfg.push_back("signed-caches");
#endif
        std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
        std::cout << "Configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
        std::cout << "Store directory: " << settings.nixStore << "\n";
        std::cout << "State directory: " << settings.nixStateDir << "\n";
    }
    throw Exit();
}

void showManPage(const string & name)
{
    restoreSignals();
    execlp("man", "man", name.c_str(), NULL);
    throw SysError(format("command 'man %1%' failed") % name.c_str());
}

int handleExceptions(const string & programName, std::function<void()> fun)
{
    ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this

    string error = ANSI_RED "error:" ANSI_NORMAL " ";
    try {
        try {
            fun();
        } catch (...) {
            /* Subtle: we have to make sure that any `interrupted'
               condition is discharged before we reach printMsg()
               below, since otherwise it will throw an (uncaught)
               exception. */
            setInterruptThrown();
            throw;
        }
    } catch (Exit & e) {
        return e.status;
    } catch (UsageError & e) {
        printError(
            format(error + "%1%\nTry '%2% --help' for more information.")
            % e.what() % programName);
        return 1;
    } catch (BaseError & e) {
        printError(format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
        if (e.prefix() != "" && !settings.showTrace)
            printError("(use '--show-trace' to show detailed location information)");
        return e.status;
    } catch (std::bad_alloc & e) {
        printError(error + "out of memory");
        return 1;
    } catch (std::exception & e) {
        printError(error + e.what());
        return 1;
    }

    return 0;
}

RunPager::RunPager()
{
    if (!isatty(STDOUT_FILENO)) return;
    char * pager = getenv("NIX_PAGER");
    if (!pager) pager = getenv("PAGER");
    if (pager && ((string) pager == "" || (string) pager == "cat")) return;

    Pipe toPager;
    toPager.create();

    pid = startProcess([&]() {
        if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("dupping stdin");
        if (!getenv("LESS"))
            setenv("LESS", "FRSXMK", 1);
        restoreSignals();
        if (pager)
            execl("/bin/sh", "sh", "-c", pager, NULL);
        execlp("pager", "pager", NULL);
        execlp("less", "less", NULL);
        execlp("more", "more", NULL);
        throw SysError(format("executing '%1%'") % pager);
    });

    pid.setKillSignal(SIGINT);

    if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
        throw SysError("dupping stdout");
}

RunPager::~RunPager()
{
    try {
        if (pid != -1) {
            std::cout.flush();
            close(STDOUT_FILENO);
            pid.wait();
        }
    } catch (...) {
        ignoreException();
    }
}

string showBytes(unsigned long long bytes)
{
    return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}

PrintFreed::~PrintFreed()
{
    if (show)
        std::cout << format("%1% store paths deleted, %2% freed\n")
            % results.paths.size()
            % showBytes(results.bytesFreed);
}

}
<|endoftext|>