<commit_before>// For compilers that supports precompilation , includes  wx/wx.h
#include  "wx/wxprec.h"

#ifndef WX_PRECOMP
#include  "wx/wx.h"
#endif

#include  "wx.h"

#include "iaxclient.h"

/* for the silly key state stuff :( */
#ifdef __WXGTK__
#include <gdk/gdk.h>
#endif

#ifdef __WXMAC__
#include <Carbon/Carbon.h>
#endif

#define LEVEL_MAX -10
#define LEVEL_MIN -50
#define DEFAULT_SILENCE_THRESHOLD 1 // positive is "auto"

IMPLEMENT_APP(IAXClient)

// event constants
enum
{
    ID_DTMF_1 = 0,
    ID_DTMF_2,
    ID_DTMF_3,
    ID_DTMF_4,
    ID_DTMF_5,
    ID_DTMF_6,
    ID_DTMF_7,
    ID_DTMF_8,
    ID_DTMF_9,
    ID_DTMF_STAR,
    ID_DTMF_O,
    ID_DTMF_POUND,

    ID_DIAL = 100,
    ID_HANG,

    ID_QUIT = 200,

    ID_PTT = 300,
    ID_MUTE,
    ID_SUPPRESS,

    CALLBACK_STATUS = 1000,
    CALLBACK_LEVELS,

    ID_MAX
};

static char *buttonlabels[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#" };

class IAXTimer : public wxTimer
{
  public:
    void IAXTimer::Notify();
};

class IAXFrame : public wxFrame
{
public:
    IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height);

    ~IAXFrame();

    void IAXFrame::OnDTMF(wxEvent &evt);
    void IAXFrame::OnDial(wxEvent &evt);
    void IAXFrame::OnHangup(wxEvent &evt);
    void IAXFrame::OnQuit(wxEvent &evt);
    void IAXFrame::OnPTTChange(wxEvent &evt);
    void IAXFrame::OnNotify(void);

    bool IAXFrame::GetPTTState();
    void IAXFrame::CheckPTT();
    void IAXFrame::SetPTT(bool state);

    wxGauge *input;
    wxGauge *output;
    IAXTimer *timer;
    wxTextCtrl *iaxDest;
    wxStaticText *muteState;

    bool pttMode;  // are we in PTT mode?
    bool pttState; // is the PTT button pressed?

    // values set by callbacks
    int	      inputLevel;
    int	      outputLevel;
    wxString  statusString;

protected:
    DECLARE_EVENT_TABLE()

#ifdef __WXGTK__
    GdkWindow *keyStateWindow;
#endif
};

static IAXFrame *theFrame;

void IAXFrame::OnNotify()
{
    static wxString lastStatus;
    static int lastInputLevel = 0;
    static int lastOutputLevel = 0;

    if(pttMode) CheckPTT();

    if(statusString != lastStatus) {
      SetStatusText(statusString);
      lastStatus = statusString;
    }

    if(lastInputLevel != inputLevel) {
      input->SetValue(inputLevel);
      lastInputLevel = inputLevel;
    }

    if(lastOutputLevel != outputLevel) {
      output->SetValue(outputLevel);
      lastOutputLevel = outputLevel;
    }
}

void IAXTimer::Notify()
{
    theFrame->OnNotify();
}

IAXFrame::IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height)
  : wxFrame((wxFrame *) NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height))
{
    wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
    wxPanel *aPanel = new wxPanel(this);
    wxButton *dialButton;

    wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *row1sizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *row3sizer = new wxBoxSizer(wxHORIZONTAL);
    pttMode = false;
    inputLevel = 0;
    outputLevel = 0;
    statusString = wxString("Welcome to IAXClient");

    /* add status bar first; otherwise, sizer doesn't take it into
     * account */
    CreateStatusBar();

    /* Set up Menus */
    /* NOTE: Mac doesn't use a File/Exit item, and Application/Quit is
	automatically added for us */

#ifndef __WXMAC__
    wxMenu *fileMenu = new wxMenu();
    fileMenu->Append(ID_QUIT, _T("E&xit\tCtrl-X"));
#endif

    wxMenu *optionsMenu = new wxMenu();
    optionsMenu->AppendCheckItem(ID_PTT, _T("Enable &Push to Talk\tCtrl-P"));

    wxMenuBar *menuBar = new wxMenuBar();

#ifndef __WXMAC__
    menuBar->Append(fileMenu, _T("&File"));
#endif
    menuBar->Append(optionsMenu, _T("&Options"));

    SetMenuBar(menuBar);

    /* DialPad Buttons */
    wxGridSizer *dialpadsizer = new wxGridSizer(3);
    for(int i=0; i<12;i++)
    {
	dialpadsizer->Add(
	  new wxButton(aPanel, i, wxString(buttonlabels[i]),
		  wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),
	    1, wxEXPAND|wxALL, 3);
    }
    row1sizer->Add(dialpadsizer,1, wxEXPAND);

    /* volume meters */
    row1sizer->Add(input  = new wxGauge(aPanel, -1, LEVEL_MAX-LEVEL_MIN, wxDefaultPosition, wxSize(15,50),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("input level")),0,wxEXPAND);

    row1sizer->Add(output  = new wxGauge(aPanel, -1, LEVEL_MAX-LEVEL_MIN, wxDefaultPosition, wxSize(15,50),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("output level")),0, wxEXPAND);

    topsizer->Add(row1sizer,1,wxEXPAND);

    /* Destination */
    topsizer->Add(iaxDest = new wxTextCtrl(aPanel, -1, wxString("guest@ast1/8068"),
	wxDefaultPosition, wxDefaultSize),0,wxEXPAND);

    /* main control buttons */
    row3sizer->Add(dialButton = new wxButton(aPanel, ID_DIAL, wxString("Dial"),
	    wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),1, wxEXPAND|wxALL, 3);

    row3sizer->Add(new wxButton(aPanel, ID_HANG, wxString("Hang Up"),
	    wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),1, wxEXPAND|wxALL, 3);

    /* make dial the default button */
    dialButton->SetDefault();
#if 0
    row3sizer->Add(quitButton = new wxButton(aPanel, 100, wxString("Quit"),
	    wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),1, wxEXPAND|wxALL, 3);
#endif

    topsizer->Add(row3sizer,0,wxEXPAND);

    topsizer->Add(muteState = new wxStaticText(aPanel,-1,"PTT Disabled",
	    wxDefaultPosition, wxDefaultSize),0,wxEXPAND);

    aPanel->SetSizer(topsizer);
    topsizer->SetSizeHints(aPanel);

    panelSizer->Add(aPanel,1,wxEXPAND);
    SetSizer(panelSizer);
    panelSizer->SetSizeHints(this);

#ifdef __WXGTK__
    // window used for getting keyboard state
    GdkWindowAttr attr;
    keyStateWindow = gdk_window_new(NULL, &attr, 0);
#endif

    timer = new IAXTimer();
    timer->Start(100);
    //output = new wxGauge(this, -1, 100);
}

bool IAXFrame::GetPTTState()
{
    bool pressed;
#ifdef __WXMAC__
    KeyMap theKeys;
    GetKeys(theKeys);
    // that's the Control Key (by experimentation!)
    pressed = theKeys[1] & 0x08;
    //fprintf(stderr, "%p %p %p %p\n", theKeys[0], theKeys[1], theKeys[2], theKeys[3]);
#else
#ifdef __WXMSW__
    pressed = GetAsyncKeyState(VK_CONTROL)&0x8000;
#else
    int x, y;
    GdkModifierType modifiers;
    gdk_window_get_pointer(keyStateWindow, &x, &y, &modifiers);
    pressed = modifiers & GDK_CONTROL_MASK;
#endif
#endif
    return pressed;
}

void IAXFrame::SetPTT(bool state)
{
	pttState = state;
	if(pttState) {
		iaxc_set_silence_threshold(-99); //unmute input
		iaxc_set_audio_output(1);  // mute output
	} else {
		iaxc_set_silence_threshold(0);  // mute input
		iaxc_set_audio_output(0);  // unmute output
	}

        muteState->SetLabel( pttState ? "Talk" : "Mute");
}

void IAXFrame::CheckPTT()
{
    bool newState = GetPTTState();
    if(newState == pttState) return;

    SetPTT(newState);
}

void IAXFrame::OnDTMF(wxEvent &evt)
{
	iaxc_send_dtmf(*buttonlabels[evt.m_id]);
}

void IAXFrame::OnDial(wxEvent &evt)
{
	iaxc_call((char *)(theFrame->iaxDest->GetValue().c_str()));
}

void IAXFrame::OnHangup(wxEvent &evt)
{
	iaxc_dump_call();
}

void IAXFrame::OnQuit(wxEvent &evt)
{
	iaxc_dump_call();
	for(int i=0;i<10;i++) {
	  iaxc_millisleep(100);
	}
	iaxc_stop_processing_thread();
	exit(0);
}

void IAXFrame::OnPTTChange(wxEvent &evt)
{
	// XXX get the actual state!
	pttMode = !pttMode;

	if(pttMode) {
		SetPTT(GetPTTState());
	} else {
		SetPTT(true);
		iaxc_set_silence_threshold(DEFAULT_SILENCE_THRESHOLD);
		iaxc_set_audio_output(0);  // unmute output
		muteState->SetLabel("PTT Disabled");
	}
}

BEGIN_EVENT_TABLE(IAXFrame, wxFrame)
	EVT_BUTTON(0,IAXFrame::OnDTMF)
	EVT_BUTTON(1,IAXFrame::OnDTMF)
	EVT_BUTTON(2,IAXFrame::OnDTMF)
	EVT_BUTTON(3,IAXFrame::OnDTMF)
	EVT_BUTTON(4,IAXFrame::OnDTMF)
	EVT_BUTTON(5,IAXFrame::OnDTMF)
	EVT_BUTTON(6,IAXFrame::OnDTMF)
	EVT_BUTTON(7,IAXFrame::OnDTMF)
	EVT_BUTTON(8,IAXFrame::OnDTMF)
	EVT_BUTTON(9,IAXFrame::OnDTMF)
	EVT_BUTTON(10,IAXFrame::OnDTMF)
	EVT_BUTTON(11,IAXFrame::OnDTMF)
	EVT_BUTTON(ID_DIAL,IAXFrame::OnDial)
	EVT_BUTTON(ID_HANG,IAXFrame::OnHangup)

	EVT_MENU(ID_QUIT,IAXFrame::OnQuit)
	EVT_MENU(ID_PTT,IAXFrame::OnPTTChange)

	EVT_MENU(ID_PTT,IAXFrame::OnPTTChange)

END_EVENT_TABLE()

IAXFrame::~IAXFrame()
{
#ifdef __WXGTK__
    gdk_window_destroy(keyStateWindow);
#endif
    iaxc_stop_processing_thread();
}

bool IAXClient::OnInit()
{
	theFrame = new IAXFrame("IAXTest", 0,0,130,220);

	theFrame->Show(TRUE);
	SetTopWindow(theFrame);

	doTestCall(0,NULL);
	iaxc_set_error_callback(status_callback);
	iaxc_set_status_callback(status_callback);

	return true;

}

extern "C" {

   /* yes, using member variables, and polling for changes
    * isn't really a nice way to do callbacks.  BUT, I've tried the
    * "right" ways, unsuccessfully:
    *
    * 1) I've tried using wxGuiMutexEnter/Leave, but that deadlocks (and it should, I guess),
    * because sometimes these _are_ called in response to GUI events (i.e. the status callback eventually
    * gets called when you press hang up.
    *
    * 2) I've tried using events and ::wxPostEvent, but that also deadlocks (at least on GTK),
    * because it calls wxWakeUpIdle, which calls wxGuiMutexEnter, which deadlocks also, for some reason.
    *
    * So, this isn't ideal, but it works, until I can figure out a better way
    */
   void status_callback(char *msg)
   {
      theFrame->statusString = wxString(msg);
   }

   int levels_callback(float input, float output)
   {

      if (input < LEVEL_MIN)
	input = LEVEL_MIN;
      else if (input > LEVEL_MAX)
	input = LEVEL_MAX;
      theFrame->inputLevel = (int)input - (LEVEL_MIN);

      if (output < LEVEL_MIN)
	output = LEVEL_MIN;
      else if (input > LEVEL_MAX)
	output = LEVEL_MAX;
      theFrame->outputLevel = (int)output - (LEVEL_MIN);
   }
}
<commit_msg>Add separate "silence suppression" menu check-item.<commit_after>// For compilers that supports precompilation , includes  wx/wx.h
#include  "wx/wxprec.h"

#ifndef WX_PRECOMP
#include  "wx/wx.h"
#endif

#include  "wx.h"

#include "iaxclient.h"

/* for the silly key state stuff :( */
#ifdef __WXGTK__
#include <gdk/gdk.h>
#endif

#ifdef __WXMAC__
#include <Carbon/Carbon.h>
#endif

#define LEVEL_MAX -10
#define LEVEL_MIN -50
#define DEFAULT_SILENCE_THRESHOLD 1 // positive is "auto"

IMPLEMENT_APP(IAXClient)

// event constants
enum
{
    ID_DTMF_1 = 0,
    ID_DTMF_2,
    ID_DTMF_3,
    ID_DTMF_4,
    ID_DTMF_5,
    ID_DTMF_6,
    ID_DTMF_7,
    ID_DTMF_8,
    ID_DTMF_9,
    ID_DTMF_STAR,
    ID_DTMF_O,
    ID_DTMF_POUND,

    ID_DIAL = 100,
    ID_HANG,

    ID_QUIT = 200,

    ID_PTT = 300,
    ID_MUTE,
    ID_SILENCE,

    CALLBACK_STATUS = 1000,
    CALLBACK_LEVELS,

    ID_MAX
};

static char *buttonlabels[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#" };

class IAXTimer : public wxTimer
{
  public:
    void IAXTimer::Notify();
};

class IAXFrame : public wxFrame
{
public:
    IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height);

    ~IAXFrame();

    void IAXFrame::OnDTMF(wxEvent &evt);
    void IAXFrame::OnDial(wxEvent &evt);
    void IAXFrame::OnHangup(wxEvent &evt);
    void IAXFrame::OnQuit(wxEvent &evt);
    void IAXFrame::OnPTTChange(wxCommandEvent &evt);
    void IAXFrame::OnSilenceChange(wxCommandEvent &evt);
    void IAXFrame::OnNotify(void);

    bool IAXFrame::GetPTTState();
    void IAXFrame::CheckPTT();
    void IAXFrame::SetPTT(bool state);

    wxGauge *input;
    wxGauge *output;
    IAXTimer *timer;
    wxTextCtrl *iaxDest;
    wxStaticText *muteState;

    bool pttMode;  // are we in PTT mode?
    bool pttState; // is the PTT button pressed?
    bool silenceMode;  // are we in silence suppression mode?

    // values set by callbacks
    int	      inputLevel;
    int	      outputLevel;
    wxString  statusString;

protected:
    DECLARE_EVENT_TABLE()

#ifdef __WXGTK__
    GdkWindow *keyStateWindow;
#endif
};

static IAXFrame *theFrame;

void IAXFrame::OnNotify()
{
    static wxString lastStatus;
    static int lastInputLevel = 0;
    static int lastOutputLevel = 0;

    if(pttMode) CheckPTT();

    if(statusString != lastStatus) {
      SetStatusText(statusString);
      lastStatus = statusString;
    }

    if(lastInputLevel != inputLevel) {
      input->SetValue(inputLevel);
      lastInputLevel = inputLevel;
    }

    if(lastOutputLevel != outputLevel) {
      output->SetValue(outputLevel);
      lastOutputLevel = outputLevel;
    }
}

void IAXTimer::Notify()
{
    theFrame->OnNotify();
}

IAXFrame::IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height)
  : wxFrame((wxFrame *) NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height))
{
    wxBoxSizer *panelSizer = new wxBoxSizer(wxVERTICAL);
    wxPanel *aPanel = new wxPanel(this);
    wxButton *dialButton;

    wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *row1sizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *row3sizer = new wxBoxSizer(wxHORIZONTAL);
    pttMode = false;
    inputLevel = 0;
    outputLevel = 0;
    statusString = wxString("Welcome to IAXClient");

    /* add status bar first; otherwise, sizer doesn't take it into
     * account */
    CreateStatusBar();

    /* Set up Menus */
    /* NOTE: Mac doesn't use a File/Exit item, and Application/Quit is
	automatically added for us */

#ifndef __WXMAC__
    wxMenu *fileMenu = new wxMenu();
    fileMenu->Append(ID_QUIT, _T("E&xit\tCtrl-X"));
#endif

    wxMenu *optionsMenu = new wxMenu();
    optionsMenu->AppendCheckItem(ID_PTT, _T("Enable &Push to Talk\tCtrl-P"));
    optionsMenu->AppendCheckItem(ID_SILENCE, _T("Enable &Silence Suppression\tCtrl-S"));

    wxMenuBar *menuBar = new wxMenuBar();

#ifndef __WXMAC__
    menuBar->Append(fileMenu, _T("&File"));
#endif
    menuBar->Append(optionsMenu, _T("&Options"));

    SetMenuBar(menuBar);

    /* DialPad Buttons */
    wxGridSizer *dialpadsizer = new wxGridSizer(3);
    for(int i=0; i<12;i++)
    {
	dialpadsizer->Add(
	  new wxButton(aPanel, i, wxString(buttonlabels[i]),
		  wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),
	    1, wxEXPAND|wxALL, 3);
    }
    row1sizer->Add(dialpadsizer,1, wxEXPAND);

    /* volume meters */
    row1sizer->Add(input  = new wxGauge(aPanel, -1, LEVEL_MAX-LEVEL_MIN, wxDefaultPosition, wxSize(15,50),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("input level")),0,wxEXPAND);

    row1sizer->Add(output  = new wxGauge(aPanel, -1, LEVEL_MAX-LEVEL_MIN, wxDefaultPosition, wxSize(15,50),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("output level")),0, wxEXPAND);

    topsizer->Add(row1sizer,1,wxEXPAND);

    /* Destination */
    topsizer->Add(iaxDest = new wxTextCtrl(aPanel, -1, wxString("guest@ast1/8068"),
	wxDefaultPosition, wxDefaultSize),0,wxEXPAND);

    /* main control buttons */
    row3sizer->Add(dialButton = new wxButton(aPanel, ID_DIAL, wxString("Dial"),
	    wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),1, wxEXPAND|wxALL, 3);

    row3sizer->Add(new wxButton(aPanel, ID_HANG, wxString("Hang Up"),
	    wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),1, wxEXPAND|wxALL, 3);

    /* make dial the default button */
    dialButton->SetDefault();
#if 0
    row3sizer->Add(quitButton = new wxButton(aPanel, 100, wxString("Quit"),
	    wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT),1, wxEXPAND|wxALL, 3);
#endif

    topsizer->Add(row3sizer,0,wxEXPAND);

    topsizer->Add(muteState = new wxStaticText(aPanel,-1,"PTT Disabled",
	    wxDefaultPosition, wxDefaultSize),0,wxEXPAND);

    aPanel->SetSizer(topsizer);
    topsizer->SetSizeHints(aPanel);

    panelSizer->Add(aPanel,1,wxEXPAND);
    SetSizer(panelSizer);
    panelSizer->SetSizeHints(this);

#ifdef __WXGTK__
    // window used for getting keyboard state
    GdkWindowAttr attr;
    keyStateWindow = gdk_window_new(NULL, &attr, 0);
#endif

    timer = new IAXTimer();
    timer->Start(100);
    //output = new wxGauge(this, -1, 100);
}

bool IAXFrame::GetPTTState()
{
    bool pressed;
#ifdef __WXMAC__
    KeyMap theKeys;
    GetKeys(theKeys);
    // that's the Control Key (by experimentation!)
    pressed = theKeys[1] & 0x08;
    //fprintf(stderr, "%p %p %p %p\n", theKeys[0], theKeys[1], theKeys[2], theKeys[3]);
#else
#ifdef __WXMSW__
    pressed = GetAsyncKeyState(VK_CONTROL)&0x8000;
#else
    int x, y;
    GdkModifierType modifiers;
    gdk_window_get_pointer(keyStateWindow, &x, &y, &modifiers);
    pressed = modifiers & GDK_CONTROL_MASK;
#endif
#endif
    return pressed;
}

void IAXFrame::SetPTT(bool state)
{
	pttState = state;
	if(pttState) {
		iaxc_set_silence_threshold(-99); //unmute input
		iaxc_set_audio_output(1);  // mute output
	} else {
		iaxc_set_silence_threshold(0);  // mute input
		iaxc_set_audio_output(0);  // unmute output
	}

        muteState->SetLabel( pttState ? "Talk" : "Mute");
}

void IAXFrame::CheckPTT()
{
    bool newState = GetPTTState();
    if(newState == pttState) return;

    SetPTT(newState);
}

void IAXFrame::OnDTMF(wxEvent &evt)
{
	iaxc_send_dtmf(*buttonlabels[evt.m_id]);
}

void IAXFrame::OnDial(wxEvent &evt)
{
	iaxc_call((char *)(theFrame->iaxDest->GetValue().c_str()));
}

void IAXFrame::OnHangup(wxEvent &evt)
{
	iaxc_dump_call();
}

void IAXFrame::OnQuit(wxEvent &evt)
{
	iaxc_dump_call();
	for(int i=0;i<10;i++) {
	  iaxc_millisleep(100);
	}
	iaxc_stop_processing_thread();
	exit(0);
}

void IAXFrame::OnPTTChange(wxCommandEvent &evt)
{
	pttMode = evt.IsChecked();

	if(pttMode) {
		SetPTT(GetPTTState());
	} else {
		SetPTT(true);
		if(silenceMode) {
			iaxc_set_silence_threshold(DEFAULT_SILENCE_THRESHOLD);
		} else {
			iaxc_set_silence_threshold(-99);
		}
		iaxc_set_audio_output(0);  // unmute output
		muteState->SetLabel("PTT Disabled");
	}
}

void IAXFrame::OnSilenceChange(wxCommandEvent &evt)
{
	// XXX get the actual state!
	silenceMode =  evt.IsChecked();

	if(pttMode) return;

	if(silenceMode) {
		iaxc_set_silence_threshold(DEFAULT_SILENCE_THRESHOLD);
	} else {
		iaxc_set_silence_threshold(-99);
	}
}

BEGIN_EVENT_TABLE(IAXFrame, wxFrame)
	EVT_BUTTON(0,IAXFrame::OnDTMF)
	EVT_BUTTON(1,IAXFrame::OnDTMF)
	EVT_BUTTON(2,IAXFrame::OnDTMF)
	EVT_BUTTON(3,IAXFrame::OnDTMF)
	EVT_BUTTON(4,IAXFrame::OnDTMF)
	EVT_BUTTON(5,IAXFrame::OnDTMF)
	EVT_BUTTON(6,IAXFrame::OnDTMF)
	EVT_BUTTON(7,IAXFrame::OnDTMF)
	EVT_BUTTON(8,IAXFrame::OnDTMF)
	EVT_BUTTON(9,IAXFrame::OnDTMF)
	EVT_BUTTON(10,IAXFrame::OnDTMF)
	EVT_BUTTON(11,IAXFrame::OnDTMF)
	EVT_BUTTON(ID_DIAL,IAXFrame::OnDial)
	EVT_BUTTON(ID_HANG,IAXFrame::OnHangup)

	EVT_MENU(ID_QUIT,IAXFrame::OnQuit)
	EVT_MENU(ID_PTT,IAXFrame::OnPTTChange)
	EVT_MENU(ID_SILENCE,IAXFrame::OnSilenceChange)

END_EVENT_TABLE()

IAXFrame::~IAXFrame()
{
#ifdef __WXGTK__
    gdk_window_destroy(keyStateWindow);
#endif
    iaxc_stop_processing_thread();
}

bool IAXClient::OnInit()
{
	theFrame = new IAXFrame("IAXTest", 0,0,130,220);

	theFrame->Show(TRUE);
	SetTopWindow(theFrame);

	doTestCall(0,NULL);
	iaxc_set_error_callback(status_callback);
	iaxc_set_status_callback(status_callback);

	return true;

}

extern "C" {

   /* yes, using member variables, and polling for changes
    * isn't really a nice way to do callbacks.  BUT, I've tried the
    * "right" ways, unsuccessfully:
    *
    * 1) I've tried using wxGuiMutexEnter/Leave, but that deadlocks (and it should, I guess),
    * because sometimes these _are_ called in response to GUI events (i.e. the status callback eventually
    * gets called when you press hang up.
    *
    * 2) I've tried using events and ::wxPostEvent, but that also deadlocks (at least on GTK),
    * because it calls wxWakeUpIdle, which calls wxGuiMutexEnter, which deadlocks also, for some reason.
    *
    * So, this isn't ideal, but it works, until I can figure out a better way
    */
   void status_callback(char *msg)
   {
      theFrame->statusString = wxString(msg);
   }

   int levels_callback(float input, float output)
   {

      if (input < LEVEL_MIN)
	input = LEVEL_MIN;
      else if (input > LEVEL_MAX)
	input = LEVEL_MAX;
      theFrame->inputLevel = (int)input - (LEVEL_MIN);

      if (output < LEVEL_MIN)
	output = LEVEL_MIN;
      else if (input > LEVEL_MAX)
	output = LEVEL_MAX;
      theFrame->outputLevel = (int)output - (LEVEL_MIN);
   }
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCommand.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

#include <string.h>
#include <ctype.h>
#include "vtkCommand.h"

// this list should only contain the initial, contiguous
// set of events and should not include UserEvent
static const char *vtkCommandEventStrings[] = {
  "NoEvent",
  "AnyEvent",
  "DeleteEvent",
  "StartEvent",
  "EndEvent",
  "ProgressEvent",
  "PickEvent",
  "StartPickEvent",
  "EndPickEvent",
  "AbortCheckEvent",
  "ExitEvent",
  "LeftButtonPressEvent",
  "LeftButtonReleaseEvent",
  "MiddleButtonPressEvent",
  "MiddleButtonReleaseEvent",
  "RightButtonPressEvent",
  "RightButtonReleaseEvent",
  "EnterEvent",
  "LeaveEvent",
  "KeyPressEvent",
  "KeyReleaseEvent",
  "CharEvent",
  "ConfigureEvent",
  "TimerEvent",
  "MouseMoveEvent",
  "ResetCameraEvent",
  "ResetCameraClippingRangeEvent",
  "ModifiedEvent",
  "WindowEvent",
  NULL
};

//----------------------------------------------------------------
vtkCommand *vtkCommand::New()
{
  return new vtkCallbackCommand;
}

const char *vtkCommand::GetStringFromEventId(unsigned long event)
{
  static unsigned long numevents = 0;

  // find length of table
  if (!numevents)
    {
    while (vtkCommandEventStrings[numevents] != NULL)
      {
      numevents++;
      }
    }

  if (event < numevents)
    {
    return vtkCommandEventStrings[event];
    }
  else if (event == vtkCommand::UserEvent)
    {
    return "UserEvent";
    }
  else
    {
    return "NoEvent";
    }
}

unsigned long vtkCommand::GetEventIdFromString(const char *event)
{
  unsigned long i;

  for (i = 0; vtkCommandEventStrings[i] != NULL; i++)
    {
    if (!strcmp(vtkCommandEventStrings[i],event))
      {
      return i;
      }
    }
  if (!strcmp("UserEvent",event))
    {
    return vtkCommand::UserEvent;
    }
  return vtkCommand::NoEvent;
}

//----------------------------------------------------------------
vtkCallbackCommand::vtkCallbackCommand()
{
  this->ClientData = NULL;
  this->Callback = NULL;
  this->ClientDataDeleteCallback = NULL;
}

vtkCallbackCommand::~vtkCallbackCommand()
{
  if (this->ClientDataDeleteCallback)
    {
    this->ClientDataDeleteCallback(this->ClientData);
    }
}

void vtkCallbackCommand::Execute(vtkObject *caller, unsigned long event,
				 void *callData)
{
  if (this->Callback)
    {
    this->Callback(caller, event, this->ClientData, callData);
    }
}

//----------------------------------------------------------------
vtkOldStyleCallbackCommand::vtkOldStyleCallbackCommand()
{
  this->ClientData = NULL;
  this->Callback = NULL;
  this->ClientDataDeleteCallback = NULL;
}

vtkOldStyleCallbackCommand::~vtkOldStyleCallbackCommand()
{
  if (this->ClientDataDeleteCallback)
    {
    this->ClientDataDeleteCallback(this->ClientData);
    }
}

void vtkOldStyleCallbackCommand::Execute(vtkObject *,unsigned long, void *)
{
  if (this->Callback)
    {
    this->Callback(this->ClientData);
    }
}

<commit_msg>ERR:Wrong string for event<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCommand.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

#include <string.h>
#include <ctype.h>
#include "vtkCommand.h"

// this list should only contain the initial, contiguous
// set of events and should not include UserEvent
static const char *vtkCommandEventStrings[] = {
  "NoEvent",
  "AnyEvent",
  "DeleteEvent",
  "StartEvent",
  "EndEvent",
  "ProgressEvent",
  "PickEvent",
  "StartPickEvent",
  "EndPickEvent",
  "AbortCheckEvent",
  "ExitEvent",
  "LeftButtonPressEvent",
  "LeftButtonReleaseEvent",
  "MiddleButtonPressEvent",
  "MiddleButtonReleaseEvent",
  "RightButtonPressEvent",
  "RightButtonReleaseEvent",
  "EnterEvent",
  "LeaveEvent",
  "KeyPressEvent",
  "KeyReleaseEvent",
  "CharEvent",
  "ConfigureEvent",
  "TimerEvent",
  "MouseMoveEvent",
  "ResetCameraEvent",
  "ResetCameraClippingRangeEvent",
  "ModifiedEvent",
  "WindowLevelEvent",
  NULL
};

//----------------------------------------------------------------
vtkCommand *vtkCommand::New()
{
  return new vtkCallbackCommand;
}

const char *vtkCommand::GetStringFromEventId(unsigned long event)
{
  static unsigned long numevents = 0;

  // find length of table
  if (!numevents)
    {
    while (vtkCommandEventStrings[numevents] != NULL)
      {
      numevents++;
      }
    }

  if (event < numevents)
    {
    return vtkCommandEventStrings[event];
    }
  else if (event == vtkCommand::UserEvent)
    {
    return "UserEvent";
    }
  else
    {
    return "NoEvent";
    }
}

unsigned long vtkCommand::GetEventIdFromString(const char *event)
{
  unsigned long i;

  for (i = 0; vtkCommandEventStrings[i] != NULL; i++)
    {
    if (!strcmp(vtkCommandEventStrings[i],event))
      {
      return i;
      }
    }
  if (!strcmp("UserEvent",event))
    {
    return vtkCommand::UserEvent;
    }
  return vtkCommand::NoEvent;
}

//----------------------------------------------------------------
vtkCallbackCommand::vtkCallbackCommand()
{
  this->ClientData = NULL;
  this->Callback = NULL;
  this->ClientDataDeleteCallback = NULL;
}

vtkCallbackCommand::~vtkCallbackCommand()
{
  if (this->ClientDataDeleteCallback)
    {
    this->ClientDataDeleteCallback(this->ClientData);
    }
}

void vtkCallbackCommand::Execute(vtkObject *caller, unsigned long event,
				 void *callData)
{
  if (this->Callback)
    {
    this->Callback(caller, event, this->ClientData, callData);
    }
}

//----------------------------------------------------------------
vtkOldStyleCallbackCommand::vtkOldStyleCallbackCommand()
{
  this->ClientData = NULL;
  this->Callback = NULL;
  this->ClientDataDeleteCallback = NULL;
}

vtkOldStyleCallbackCommand::~vtkOldStyleCallbackCommand()
{
  if (this->ClientDataDeleteCallback)
    {
    this->ClientDataDeleteCallback(this->ClientData);
    }
}

void vtkOldStyleCallbackCommand::Execute(vtkObject *,unsigned long, void *)
{
  if (this->Callback)
    {
    this->Callback(this->ClientData);
    }
}

<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 *
 * Implements the mount helper.
 * Note: meaning of return codes is speficied by mount command.
 */

#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/wait.h>

#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>

#include "util.h"
#include "options.h"
#include "sanitizer.h"
#include "platform.h"

using namespace std;  // NOLINT

static void Usage(int output_dest) {
  LogCvmfs(kLogCvmfs, output_dest,
           "Mount helper for CernVM-FS.  Used my mount(8)\n"
           "Mandatory arguments:\n"
           "  repository name: <repository>\n"
           "  mountpoint of the repository: <mountpoint>\n"
           "Options:\n"
           "  -o <mount options>\n"
           "  -f dry run, just prints out the mount command\n"
           "  -h print this help");
}

static void AddMountOption(const string &option,
                           vector<string> *mount_options)
{
  mount_options->push_back(option);
}

static string MkFqrn(const string &repository) {
  const string::size_type idx = repository.find_last_of('.');
  if (idx == string::npos) {
    string domain;
    options::GetValue("CVMFS_DEFAULT_DOMAIN", &domain);
    return repository + "." + domain;
  }
  return repository;
}

static bool CheckFuse() {
  string fuse_device;
  int retval;
#ifdef __APPLE__
  retval = system("/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs");
  if (retval != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed loading OSX Fuse");
    return false;
  }
  fuse_device = "/dev/osxfuse0";
#else
  fuse_device = "/dev/fuse";
#endif
  platform_stat64 info;
  retval = platform_stat(fuse_device.c_str(), &info);
  if ((retval != 0) || !S_ISCHR(info.st_mode)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Fuse not loaded");
    return false;
  }
  return true;
}

static bool CheckStrictMount(const string &fqrn) {
  string param_strict_mount;
  if (options::GetValue("CVMFS_STRICT_MOUNT", &param_strict_mount) &&
      options::IsOn(param_strict_mount))
  {
    string repository_list;
    options::GetValue("CVMFS_REPOSITORIES", &repository_list);
    vector<string> repositories = SplitString(repository_list, ',');
    for (unsigned i = 0; i < repositories.size(); ++i) {
      if (MkFqrn(repositories[i]) == fqrn)
        return true;
    }
    LogCvmfs(kLogCvmfs, kLogStderr, "Not allowed to mount %s, "
             "add it to CVMFS_REPOSITORIES", fqrn.c_str());
    return false;
  }
  return true;
}

static bool CheckProxy() {
  string param;
  int retval = options::GetValue("CVMFS_HTTP_PROXY", &param);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_HTTP_PROXY required");
    return false;
  }
  return true;
}

static bool CheckConcurrentMount(const string &fqrn, const string &cachedir) {
  // Try connecting to cvmfs_io socket
  int socket_fd = ConnectSocket(cachedir + "/cvmfs_io." + fqrn);
  if (socket_fd < 0)
    return true;

  // There is a repository mounted, find out the mount point
  SendMsg2Socket(socket_fd, "mountpoint");
  string mountpoint;
  char buf;
  while (read(socket_fd, &buf, 1) == 1) {
    mountpoint.push_back(buf);
  }
  close(socket_fd);
  int output_flags = kLogStderr;
  if (!mountpoint.empty() && (mountpoint[mountpoint.length()-1] == '\n'))
    output_flags |= kLogNoLinebreak;
  LogCvmfs(kLogCvmfs, output_flags, "Repository %s is already mounted on %s",
           fqrn.c_str(), mountpoint.c_str());
  return false;
}

static bool GetCacheDir(const string &fqrn, string *cachedir) {
  string param;
  int retval = options::GetValue("CVMFS_CACHE_BASE", &param);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_CACHE_BASE required");
    return false;
  }
  *cachedir = MakeCanonicalPath(param);
  if (options::GetValue("CVMFS_SHARED_CACHE", &param) &&
      options::IsOn(param))
  {
    *cachedir = *cachedir + "/shared";
  } else {
    *cachedir = *cachedir + "/" + fqrn;
  }
  return true;
}

static bool GetCvmfsUser(string *cvmfs_user) {
  string param;
  int retval = options::GetValue("CVMFS_USER", &param);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_USER required");
    return false;
  }
  *cvmfs_user = param;  // No sanitation; due to PAM, username can be anything
  return true;
}

int main(int argc, char **argv) {
  bool dry_run = false;
  vector<string> mount_options;

  // Option parsing
  char c;
  while ((c = getopt(argc, argv, "vfnho:")) != -1) {
    switch (c) {
      case 'f':
        dry_run = true;
        break;
      case 'n':
        LogCvmfs(kLogCvmfs, kLogStdout, "Note: fusermount _does_ modify "
                 "/etc/mtab in case it is writable.");
        // Fall through
      case 'v':
        break;
      case 'h':
        Usage(kLogStdout);
        return 0;
      case 'o':
        AddMountOption(optarg, &mount_options);
        break;
      default:
        Usage(kLogStderr);
        return 1;
    }
  }
  if (optind+2 != argc) {
    Usage(kLogStderr);
    return 1;
  }

  string device = argv[optind];
  // For Ubuntu 8.04 automounter
  if (HasPrefix(device, "/cvmfs/", false))
    device = device.substr(7);
  sanitizer::RepositorySanitizer sanitizer;
  if (!sanitizer.IsValid(device)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Invalid repository: %s", device.c_str());
    return 1;
  }
  string mountpoint = argv[optind+1];

  options::Init();
  options::ParseDefault("");
  const string fqrn = MkFqrn(device);
  options::ParseDefault(fqrn);

  bool retval;
  int sysret;
  string cvmfs_user;
  string cachedir;
  // Environment checks
  retval = GetCacheDir(fqrn, &cachedir);
  if (!retval) return 1;
  retval = GetCvmfsUser(&cvmfs_user);
  if (!retval) return 1;
  retval = CheckFuse();
  if (!retval) return 1;
  retval = CheckStrictMount(fqrn);
  if (!retval) return 1;
  retval = CheckProxy();
  if (!retval) return 1;
  // This is not a sure thing.  When the CVMFS_CACHE_BASE parameter is changed
  // two repositories can get mounted concurrently (but that should not hurt).
  // If the same repository is mounted multiple times at the same time, there
  // is a race here.  Eventually, only one repository will be mounted while the
  // other cvmfs processes block on a file lock in the cache.
  retval = CheckConcurrentMount(fqrn, cachedir);
  if (!retval) return 1;

  // Retrieve cvmfs uid/gid and fuse gid if exists
  uid_t uid_cvmfs;
  gid_t gid_cvmfs;
  gid_t gid_fuse;
  bool has_fuse_group = false;
  retval = GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to find user %s in passwd database",
             cvmfs_user.c_str());
    return 1;
  }
  has_fuse_group = GetGidOf("fuse", &gid_fuse);

  // Prepare cache directory
  retval = MkdirDeep(cachedir, 0755);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create cache directory %s",
             cachedir.c_str());
    return 1;
  }
  sysret = chown(cachedir.c_str(), uid_cvmfs, 0);
  if (sysret != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to transfer ownership of %s to %s",
             cachedir.c_str(), cvmfs_user.c_str());
  }

  AddMountOption("fsname=cvmfs2", &mount_options);
  AddMountOption("allow_other", &mount_options);
  AddMountOption("grab_mountpoint", &mount_options);
  AddMountOption("uid=" + StringifyInt(uid_cvmfs), &mount_options);
  AddMountOption("gid=" + StringifyInt(gid_cvmfs), &mount_options);
  if (options::IsDefined("CVMFS_DEBUGLOG"))
    AddMountOption("debug", &mount_options);

  const string cvmfs_binary = "/usr/bin/cvmfs2";;

  // Dry run early exit
  if (dry_run) {
    string cmd = cvmfs_binary + " -o " + JoinStrings(mount_options, ",") +
                 " " + fqrn + " " + mountpoint;
    if (has_fuse_group) {
      cmd = "sg fuse -c \"" + cmd + "\"";
    }
    LogCvmfs(kLogCvmfs, kLogStdout, "%s", cmd.c_str());
    return 0;
  }

  // Real mount, add supplementary fuse group
  if (has_fuse_group) {
    retval = AddGroup2Persona(gid_fuse);
    if (!retval) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add fuse to "
               " the list of supplementary groups");
      return 1;
    }
  }

  // Exec cvmfs2, from here on errors return 32 (mount error)
  int fd_stdin, fd_stdout, fd_stderr;
  pid_t pid_cvmfs;
  vector<string> argv;
  argv.push_back("-o");
  argv.push_back(JoinStrings(mount_options, ","));
  argv.push_back(fqrn);
  argv.push_back(mountpoint);
  retval = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr,
                         cvmfs_binary, argv, false, &pid_cvmfs);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to launch %s",
             cvmfs_binary.c_str());
    return 32;
  }
  close(fd_stdin);

  // Print stdout / stderr and collect exit code
  int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
  fd_set readfds;
  bool stdout_open = true;
  bool stderr_open = true;
  do {
    FD_ZERO(&readfds);
    if (stdout_open) FD_SET(fd_stdout, &readfds);
    if (stderr_open) FD_SET(fd_stderr, &readfds);
    do {
      retval = select(nfds, &readfds, NULL, NULL, NULL);
      if ((retval == -1) && (errno != EINTR)) {
        LogCvmfs(kLogCvmfs, kLogStderr, "Failed to pipe stdout/stderr");
        return 32;
      }
      if (retval > 0)
        break;
    } while (true);
    char buf;
    int num_bytes;
    if (FD_ISSET(fd_stdout, &readfds)) {
      num_bytes = read(fd_stdout, &buf, 1);
      switch (num_bytes) {
        case 0:
          stdout_open = false;
          break;
        case 1:
          LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak, "%c", buf);
          break;
        default:
          LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stdout");
          return 32;
      }
    }
    if (FD_ISSET(fd_stderr, &readfds)) {
      num_bytes = read(fd_stderr, &buf, 1);
      switch (num_bytes) {
        case 0:
          stderr_open = false;
          break;
        case 1:
          LogCvmfs(kLogCvmfs, kLogStderr | kLogNoLinebreak, "%c", buf);
          break;
        default:
          LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stderr");
          return 32;
      }
    }
  } while (stdout_open || stderr_open);
  close(fd_stdout);
  close(fd_stderr);

  int status;
  retval = waitpid(pid_cvmfs, &status, 0);
  if (retval == -1) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading return code");
    return 32;
  }
  if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
    return 0;

  return 32;
}
<commit_msg>FIX: compile error due to veriable re-declaration<commit_after>/**
 * This file is part of the CernVM File System.
 *
 * Implements the mount helper.
 * Note: meaning of return codes is speficied by mount command.
 */

#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/wait.h>

#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>

#include "util.h"
#include "options.h"
#include "sanitizer.h"
#include "platform.h"

using namespace std;  // NOLINT

static void Usage(int output_dest) {
  LogCvmfs(kLogCvmfs, output_dest,
           "Mount helper for CernVM-FS.  Used my mount(8)\n"
           "Mandatory arguments:\n"
           "  repository name: <repository>\n"
           "  mountpoint of the repository: <mountpoint>\n"
           "Options:\n"
           "  -o <mount options>\n"
           "  -f dry run, just prints out the mount command\n"
           "  -h print this help");
}

static void AddMountOption(const string &option,
                           vector<string> *mount_options)
{
  mount_options->push_back(option);
}

static string MkFqrn(const string &repository) {
  const string::size_type idx = repository.find_last_of('.');
  if (idx == string::npos) {
    string domain;
    options::GetValue("CVMFS_DEFAULT_DOMAIN", &domain);
    return repository + "." + domain;
  }
  return repository;
}

static bool CheckFuse() {
  string fuse_device;
  int retval;
#ifdef __APPLE__
  retval = system("/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs");
  if (retval != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed loading OSX Fuse");
    return false;
  }
  fuse_device = "/dev/osxfuse0";
#else
  fuse_device = "/dev/fuse";
#endif
  platform_stat64 info;
  retval = platform_stat(fuse_device.c_str(), &info);
  if ((retval != 0) || !S_ISCHR(info.st_mode)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Fuse not loaded");
    return false;
  }
  return true;
}

static bool CheckStrictMount(const string &fqrn) {
  string param_strict_mount;
  if (options::GetValue("CVMFS_STRICT_MOUNT", &param_strict_mount) &&
      options::IsOn(param_strict_mount))
  {
    string repository_list;
    options::GetValue("CVMFS_REPOSITORIES", &repository_list);
    vector<string> repositories = SplitString(repository_list, ',');
    for (unsigned i = 0; i < repositories.size(); ++i) {
      if (MkFqrn(repositories[i]) == fqrn)
        return true;
    }
    LogCvmfs(kLogCvmfs, kLogStderr, "Not allowed to mount %s, "
             "add it to CVMFS_REPOSITORIES", fqrn.c_str());
    return false;
  }
  return true;
}

static bool CheckProxy() {
  string param;
  int retval = options::GetValue("CVMFS_HTTP_PROXY", &param);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_HTTP_PROXY required");
    return false;
  }
  return true;
}

static bool CheckConcurrentMount(const string &fqrn, const string &cachedir) {
  // Try connecting to cvmfs_io socket
  int socket_fd = ConnectSocket(cachedir + "/cvmfs_io." + fqrn);
  if (socket_fd < 0)
    return true;

  // There is a repository mounted, find out the mount point
  SendMsg2Socket(socket_fd, "mountpoint");
  string mountpoint;
  char buf;
  while (read(socket_fd, &buf, 1) == 1) {
    mountpoint.push_back(buf);
  }
  close(socket_fd);
  int output_flags = kLogStderr;
  if (!mountpoint.empty() && (mountpoint[mountpoint.length()-1] == '\n'))
    output_flags |= kLogNoLinebreak;
  LogCvmfs(kLogCvmfs, output_flags, "Repository %s is already mounted on %s",
           fqrn.c_str(), mountpoint.c_str());
  return false;
}

static bool GetCacheDir(const string &fqrn, string *cachedir) {
  string param;
  int retval = options::GetValue("CVMFS_CACHE_BASE", &param);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_CACHE_BASE required");
    return false;
  }
  *cachedir = MakeCanonicalPath(param);
  if (options::GetValue("CVMFS_SHARED_CACHE", &param) &&
      options::IsOn(param))
  {
    *cachedir = *cachedir + "/shared";
  } else {
    *cachedir = *cachedir + "/" + fqrn;
  }
  return true;
}

static bool GetCvmfsUser(string *cvmfs_user) {
  string param;
  int retval = options::GetValue("CVMFS_USER", &param);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "CVMFS_USER required");
    return false;
  }
  *cvmfs_user = param;  // No sanitation; due to PAM, username can be anything
  return true;
}

int main(int argc, char **argv) {
  bool dry_run = false;
  vector<string> mount_options;

  // Option parsing
  char c;
  while ((c = getopt(argc, argv, "vfnho:")) != -1) {
    switch (c) {
      case 'f':
        dry_run = true;
        break;
      case 'n':
        LogCvmfs(kLogCvmfs, kLogStdout, "Note: fusermount _does_ modify "
                 "/etc/mtab in case it is writable.");
        // Fall through
      case 'v':
        break;
      case 'h':
        Usage(kLogStdout);
        return 0;
      case 'o':
        AddMountOption(optarg, &mount_options);
        break;
      default:
        Usage(kLogStderr);
        return 1;
    }
  }
  if (optind+2 != argc) {
    Usage(kLogStderr);
    return 1;
  }

  string device = argv[optind];
  // For Ubuntu 8.04 automounter
  if (HasPrefix(device, "/cvmfs/", false))
    device = device.substr(7);
  sanitizer::RepositorySanitizer sanitizer;
  if (!sanitizer.IsValid(device)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Invalid repository: %s", device.c_str());
    return 1;
  }
  string mountpoint = argv[optind+1];

  options::Init();
  options::ParseDefault("");
  const string fqrn = MkFqrn(device);
  options::ParseDefault(fqrn);

  bool retval;
  int sysret;
  string cvmfs_user;
  string cachedir;
  // Environment checks
  retval = GetCacheDir(fqrn, &cachedir);
  if (!retval) return 1;
  retval = GetCvmfsUser(&cvmfs_user);
  if (!retval) return 1;
  retval = CheckFuse();
  if (!retval) return 1;
  retval = CheckStrictMount(fqrn);
  if (!retval) return 1;
  retval = CheckProxy();
  if (!retval) return 1;
  // This is not a sure thing.  When the CVMFS_CACHE_BASE parameter is changed
  // two repositories can get mounted concurrently (but that should not hurt).
  // If the same repository is mounted multiple times at the same time, there
  // is a race here.  Eventually, only one repository will be mounted while the
  // other cvmfs processes block on a file lock in the cache.
  retval = CheckConcurrentMount(fqrn, cachedir);
  if (!retval) return 1;

  // Retrieve cvmfs uid/gid and fuse gid if exists
  uid_t uid_cvmfs;
  gid_t gid_cvmfs;
  gid_t gid_fuse;
  bool has_fuse_group = false;
  retval = GetUidOf(cvmfs_user, &uid_cvmfs, &gid_cvmfs);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to find user %s in passwd database",
             cvmfs_user.c_str());
    return 1;
  }
  has_fuse_group = GetGidOf("fuse", &gid_fuse);

  // Prepare cache directory
  retval = MkdirDeep(cachedir, 0755);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to create cache directory %s",
             cachedir.c_str());
    return 1;
  }
  sysret = chown(cachedir.c_str(), uid_cvmfs, 0);
  if (sysret != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to transfer ownership of %s to %s",
             cachedir.c_str(), cvmfs_user.c_str());
  }

  AddMountOption("fsname=cvmfs2", &mount_options);
  AddMountOption("allow_other", &mount_options);
  AddMountOption("grab_mountpoint", &mount_options);
  AddMountOption("uid=" + StringifyInt(uid_cvmfs), &mount_options);
  AddMountOption("gid=" + StringifyInt(gid_cvmfs), &mount_options);
  if (options::IsDefined("CVMFS_DEBUGLOG"))
    AddMountOption("debug", &mount_options);

  const string cvmfs_binary = "/usr/bin/cvmfs2";;

  // Dry run early exit
  if (dry_run) {
    string cmd = cvmfs_binary + " -o " + JoinStrings(mount_options, ",") +
                 " " + fqrn + " " + mountpoint;
    if (has_fuse_group) {
      cmd = "sg fuse -c \"" + cmd + "\"";
    }
    LogCvmfs(kLogCvmfs, kLogStdout, "%s", cmd.c_str());
    return 0;
  }

  // Real mount, add supplementary fuse group
  if (has_fuse_group) {
    retval = AddGroup2Persona(gid_fuse);
    if (!retval) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to add fuse to "
               " the list of supplementary groups");
      return 1;
    }
  }

  // Exec cvmfs2, from here on errors return 32 (mount error)
  int fd_stdin, fd_stdout, fd_stderr;
  pid_t pid_cvmfs;
  vector<string> cvmfs_args;
  cvmfs_args.push_back("-o");
  cvmfs_args.push_back(JoinStrings(mount_options, ","));
  cvmfs_args.push_back(fqrn);
  cvmfs_args.push_back(mountpoint);
  retval = ExecuteBinary(&fd_stdin, &fd_stdout, &fd_stderr,
                         cvmfs_binary, cvmfs_args, false, &pid_cvmfs);
  if (!retval) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to launch %s",
             cvmfs_binary.c_str());
    return 32;
  }
  close(fd_stdin);

  // Print stdout / stderr and collect exit code
  int nfds = fd_stdout > fd_stderr ? fd_stdout + 1 : fd_stderr + 1;
  fd_set readfds;
  bool stdout_open = true;
  bool stderr_open = true;
  do {
    FD_ZERO(&readfds);
    if (stdout_open) FD_SET(fd_stdout, &readfds);
    if (stderr_open) FD_SET(fd_stderr, &readfds);
    do {
      retval = select(nfds, &readfds, NULL, NULL, NULL);
      if ((retval == -1) && (errno != EINTR)) {
        LogCvmfs(kLogCvmfs, kLogStderr, "Failed to pipe stdout/stderr");
        return 32;
      }
      if (retval > 0)
        break;
    } while (true);
    char buf;
    int num_bytes;
    if (FD_ISSET(fd_stdout, &readfds)) {
      num_bytes = read(fd_stdout, &buf, 1);
      switch (num_bytes) {
        case 0:
          stdout_open = false;
          break;
        case 1:
          LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak, "%c", buf);
          break;
        default:
          LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stdout");
          return 32;
      }
    }
    if (FD_ISSET(fd_stderr, &readfds)) {
      num_bytes = read(fd_stderr, &buf, 1);
      switch (num_bytes) {
        case 0:
          stderr_open = false;
          break;
        case 1:
          LogCvmfs(kLogCvmfs, kLogStderr | kLogNoLinebreak, "%c", buf);
          break;
        default:
          LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading stderr");
          return 32;
      }
    }
  } while (stdout_open || stderr_open);
  close(fd_stdout);
  close(fd_stderr);

  int status;
  retval = waitpid(pid_cvmfs, &status, 0);
  if (retval == -1) {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed reading return code");
    return 32;
  }
  if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
    return 0;

  return 32;
}
<|endoftext|>


<commit_before>/*-----------------------------------------------------------------------------

 Copyright 2017 Hopsan Group

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

 The full license is available in the file LICENSE.
 For details about the 'Hopsan Group' or information about Authors and
 Contributors see the HOPSANGROUP and AUTHORS files that are located in
 the Hopsan source code root directory.

-----------------------------------------------------------------------------*/

#include "fmu_hopsan.h"
#include "HopsanCore.h"
#include "HopsanEssentials.h"
#include <string>
#include "model.hpp"
#include <cassert>

namespace {

static double fmu_time=0;
static hopsan::ComponentSystem *spCoreComponentSystem = 0;
static std::vector<std::string> sComponentNames;
hopsan::HopsanEssentials gHopsanCore;

double *dataPtrs[<<<nports>>>];

std::string parseResourceLocation(std::string uri)
{
    // The resource location is an URI according to rfc3986 on the following format
    // schema://authority/path or schema:/path
    // authority is expected to be empty if included
    // only the 'file' schema is supported by Hopsan
    std::string::size_type se = uri.find_first_of(':');
    std::string schema = uri.substr(0,se);
    // If the next two chars are // then authority is included (may be empty)
    std::string::size_type pb;
    if (uri.substr(se+1,2) == "//") {
        pb = uri.find_first_of('/', se+3);
    } else {
        pb = uri.find_first_of('/', se);
    }
    // Now we know were the path begins (pb), but is it a unix or windows path
    // Check windows
    if (uri.substr(pb+2,2) == ":/") {
        // Skip first /
        pb++;
    }
    std::string path = uri.substr(pb);
#ifdef _WIN32
    std::string::size_type i = path.find_first_of('/');
    while (i != std::string::npos) {
        path.replace(i, 1, 1, '\\');
        i = path.find_first_of('/');
    }
#endif
    return path;
}
}

extern "C" {

int hopsan_instantiate(const char *resourceLocation)
{
    double startT, stopT;      // Dummy variables
    spCoreComponentSystem = gHopsanCore.loadHMFModel(getModelString().c_str(), startT, stopT);
    if (spCoreComponentSystem)
    {
        std::string rl = parseResourceLocation(resourceLocation);
        spCoreComponentSystem->addSearchPath(rl.c_str());

        // Get pointers to I/O data variables
        <<<setdataptrs>>>

        // Initialize system
        spCoreComponentSystem->setDesiredTimestep(<<<timestep>>>);
        spCoreComponentSystem->setNumLogSamples(0);
        //! @todo disableLog does not work without setNumLogsamples0
        spCoreComponentSystem->disableLog();
        if (spCoreComponentSystem->checkModelBeforeSimulation())
        {
            return 1; // C true
        }
    }
    return 0;  // C false
}

int hopsan_initialize(double startT, double stopT)
{
    return spCoreComponentSystem->initialize(startT, stopT) ? 1 : 0;
}

void hopsan_simulate(double stopTime)
{
    spCoreComponentSystem->simulate(stopTime);
}

void hopsan_finalize()
{
    spCoreComponentSystem->finalize();
}

int hopsan_has_message()
{
    return (gHopsanCore.checkMessage() > 0) ? 1 : 0;
}

void hopsan_get_message(hopsan_message_callback_t message_callback, void* userState)
{
    hopsan::HString message, type, tag;
    gHopsanCore.getMessage(message, type, tag);

    // Replace any # with ## (# is reserved by FMI for value references)
    // # is used as escape character in this case
    message.replace("#", "##");

    // Replace any single % since we do not use printf format strings inside Hopsan
    // The FMI standard assuems that message is a printf format string
    // Use %% to print %
    message.replace("%", "%%");

    message_callback(message.c_str(), type.c_str(), userState);
}

double hopsan_get_real(int vr)
{
    return (*dataPtrs[vr]);
}

int hopsan_get_integer(int vr)
{
    //Write code here
}

int hopsan_get_boolean(int vr)
{
    //Write code here
}

const char* hopsan_get_string(int vr)
{
    //Write code here
}

void hopsan_set_real(int vr, double value)
{
    (*dataPtrs[vr]) = value;
}

void hopsan_set_integer(int vr, int value)
{
    //Write code here
}

void hopsan_set_boolean(int vr, int value)
{
    //Write code here
}

void hopsan_set_string(int vr, const char* value)
{
    //Write code here
}

}
<commit_msg>Return something to avoid Warnings with GCC 8 when exporting FMU<commit_after>/*-----------------------------------------------------------------------------

 Copyright 2017 Hopsan Group

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

 The full license is available in the file LICENSE.
 For details about the 'Hopsan Group' or information about Authors and
 Contributors see the HOPSANGROUP and AUTHORS files that are located in
 the Hopsan source code root directory.

-----------------------------------------------------------------------------*/

#include "fmu_hopsan.h"
#include "HopsanCore.h"
#include "HopsanEssentials.h"
#include <string>
#include "model.hpp"
#include <cassert>

namespace {

static double fmu_time=0;
static hopsan::ComponentSystem *spCoreComponentSystem = 0;
static std::vector<std::string> sComponentNames;
hopsan::HopsanEssentials gHopsanCore;

double *dataPtrs[<<<nports>>>];

std::string parseResourceLocation(std::string uri)
{
    // The resource location is an URI according to rfc3986 on the following format
    // schema://authority/path or schema:/path
    // authority is expected to be empty if included
    // only the 'file' schema is supported by Hopsan
    std::string::size_type se = uri.find_first_of(':');
    std::string schema = uri.substr(0,se);
    // If the next two chars are // then authority is included (may be empty)
    std::string::size_type pb;
    if (uri.substr(se+1,2) == "//") {
        pb = uri.find_first_of('/', se+3);
    } else {
        pb = uri.find_first_of('/', se);
    }
    // Now we know were the path begins (pb), but is it a unix or windows path
    // Check windows
    if (uri.substr(pb+2,2) == ":/") {
        // Skip first /
        pb++;
    }
    std::string path = uri.substr(pb);
#ifdef _WIN32
    std::string::size_type i = path.find_first_of('/');
    while (i != std::string::npos) {
        path.replace(i, 1, 1, '\\');
        i = path.find_first_of('/');
    }
#endif
    return path;
}
}

extern "C" {

int hopsan_instantiate(const char *resourceLocation)
{
    double startT, stopT;      // Dummy variables
    spCoreComponentSystem = gHopsanCore.loadHMFModel(getModelString().c_str(), startT, stopT);
    if (spCoreComponentSystem)
    {
        std::string rl = parseResourceLocation(resourceLocation);
        spCoreComponentSystem->addSearchPath(rl.c_str());

        // Get pointers to I/O data variables
        <<<setdataptrs>>>

        // Initialize system
        spCoreComponentSystem->setDesiredTimestep(<<<timestep>>>);
        spCoreComponentSystem->setNumLogSamples(0);
        //! @todo disableLog does not work without setNumLogsamples0
        spCoreComponentSystem->disableLog();
        if (spCoreComponentSystem->checkModelBeforeSimulation())
        {
            return 1; // C true
        }
    }
    return 0;  // C false
}

int hopsan_initialize(double startT, double stopT)
{
    return spCoreComponentSystem->initialize(startT, stopT) ? 1 : 0;
}

void hopsan_simulate(double stopTime)
{
    spCoreComponentSystem->simulate(stopTime);
}

void hopsan_finalize()
{
    spCoreComponentSystem->finalize();
}

int hopsan_has_message()
{
    return (gHopsanCore.checkMessage() > 0) ? 1 : 0;
}

void hopsan_get_message(hopsan_message_callback_t message_callback, void* userState)
{
    hopsan::HString message, type, tag;
    gHopsanCore.getMessage(message, type, tag);

    // Replace any # with ## (# is reserved by FMI for value references)
    // # is used as escape character in this case
    message.replace("#", "##");

    // Replace any single % since we do not use printf format strings inside Hopsan
    // The FMI standard assuems that message is a printf format string
    // Use %% to print %
    message.replace("%", "%%");

    message_callback(message.c_str(), type.c_str(), userState);
}

double hopsan_get_real(int vr)
{
    return (*dataPtrs[vr]);
}

int hopsan_get_integer(int vr)
{
    //Write code here
    return -1;
}

int hopsan_get_boolean(int vr)
{
    //Write code here
    return false;
}

const char* hopsan_get_string(int vr)
{
    //Write code here
    return "";
}

void hopsan_set_real(int vr, double value)
{
    (*dataPtrs[vr]) = value;
}

void hopsan_set_integer(int vr, int value)
{
    //Write code here
}

void hopsan_set_boolean(int vr, int value)
{
    //Write code here
}

void hopsan_set_string(int vr, const char* value)
{
    //Write code here
}

}
<|endoftext|>


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

#ifndef SESAME_VERSION_HPP
#define SESAME_VERSION_HPP

#include <cstdint>

namespace sesame {

const uint32_t VERSION_MAJOR = 0;
const uint32_t VERSION_MINOR = 3;
const uint32_t VERSION_BUGFIX = 0;

namespace
{
   static const String getVersionString()
   {
      StringStream s;
      s << "Sesame ";
      s << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUGFIX;
      s << " - Copyright (c), 2015 Karsten Heinze";

      return s.str();
   }
}

static const String VERSION_STRING( getVersionString() );

}

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

#ifndef SESAME_VERSION_HPP
#define SESAME_VERSION_HPP

#include <cstdint>

namespace sesame {

const uint32_t VERSION_MAJOR = 0;
const uint32_t VERSION_MINOR = 3;
const uint32_t VERSION_BUGFIX = 1;

namespace
{
   static const String getVersionString()
   {
      StringStream s;
      s << "Sesame ";
      s << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_BUGFIX;
      s << " - Copyright (c), 2015 Karsten Heinze";

      return s.str();
   }
}

static const String VERSION_STRING( getVersionString() );

}

#endif
<|endoftext|>


<commit_before>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */

/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Base energy PK.

This provides the base of an advection-diffusion equation for energy.

------------------------------------------------------------------------- */

#ifndef PKS_ENERGY_BASE_HH_
#define PKS_ENERGY_BASE_HH_

#include "pk_factory.hh"
#include "MatrixMFD.hh"
#include "pk_physical_bdf_base.hh"
#include "upwinding.hh"

namespace Amanzi {

// forward declarations
namespace Operators { class Advection; }
namespace Functions { class BoundaryFunction; }

namespace Energy {

class EnergyBase : public PKPhysicalBDFBase {

public:
  EnergyBase(const Teuchos::RCP<Teuchos::ParameterList>& plist,
             Teuchos::ParameterList& FElist,
             const Teuchos::RCP<TreeVector>& solution) :
      PKDefaultBase(plist, FElist, solution),
      PKPhysicalBDFBase(plist, FElist, solution),
      modify_predictor_with_consistent_faces_(false),
      coupled_to_subsurface_via_temp_(false),
      coupled_to_subsurface_via_flux_(false),
      coupled_to_surface_via_temp_(false),
      coupled_to_surface_via_flux_(false),
      niter_(0),
      explicit_advection_(false) {}

  // Virtual destructor
  virtual ~EnergyBase() {}

  // EnergyBase is a PK
  // -- Setup data
  virtual void setup(const Teuchos::Ptr<State>& S);

  // -- Initialize owned (dependent) variables.
  virtual void initialize(const Teuchos::Ptr<State>& S);

  // -- Commit any secondary (dependent) variables.
  virtual void commit_state(double dt, const Teuchos::RCP<State>& S);

  // -- Calculate any diagnostics prior to doing vis
  virtual void calculate_diagnostics(const Teuchos::RCP<State>& S) {}

  // EnergyBase is a BDFFnBase
  // computes the non-linear functional f = f(t,u,udot)
  virtual void Functional(double t_old, double t_new, Teuchos::RCP<TreeVector> u_old,
                   Teuchos::RCP<TreeVector> u_new, Teuchos::RCP<TreeVector> f);

  // applies preconditioner to u and returns the result in Pu
  virtual void ApplyPreconditioner(Teuchos::RCP<const TreeVector> u, Teuchos::RCP<TreeVector> Pu);

  // updates the preconditioner
  virtual void UpdatePreconditioner(double t, Teuchos::RCP<const TreeVector> up, double h);

  // problems with temperatures -- setting a range of admissible temps
  virtual bool IsAdmissible(Teuchos::RCP<const TreeVector> up);

  // error monitor
  virtual double ErrorNorm(Teuchos::RCP<const TreeVector> u,
                       Teuchos::RCP<const TreeVector> du);

  virtual bool ModifyPredictor(double h, Teuchos::RCP<const TreeVector> u0,
          Teuchos::RCP<TreeVector> u);

  // evaluating consistent faces for given BCs and cell values
  virtual void CalculateConsistentFaces(const Teuchos::Ptr<CompositeVector>& u);

protected:
  // These must be provided by the deriving PK.
  // -- setup the evaluators
  virtual void SetupPhysicalEvaluators_(const Teuchos::Ptr<State>& S) = 0;

  // -- get enthalpy as a function of Dirichlet boundary data.  Note that this
  //    will get replaced by a better system when we get maps on the boundary
  //    faces.
  virtual void ApplyDirichletBCsToEnthalpy_(const Teuchos::Ptr<State>& S,
          const Teuchos::Ptr<CompositeVector>& enth) = 0;

  // -- Add any source terms into the residual.
  virtual void AddSources_(const Teuchos::Ptr<State>& S,
                           const Teuchos::Ptr<CompositeVector>& f);
  virtual void AddSourcesToPrecon_(const Teuchos::Ptr<State>& S, double h);

  // Standard methods
  virtual void SetupEnergy_(const Teuchos::Ptr<State>& S);

  // Upwinding conductivities
  virtual bool UpdateConductivityData_(const Teuchos::Ptr<State>& S);

  // boundary condition members
  virtual void UpdateBoundaryConditions_();
  virtual void ApplyBoundaryConditions_(const Teuchos::RCP<CompositeVector>& temperature);

  // physical methods
  // -- accumulation of energy
  virtual void AddAccumulation_(const Teuchos::Ptr<CompositeVector>& f);

  // -- advection of enthalpy
  virtual void AddAdvection_(const Teuchos::Ptr<State>& S,
                     const Teuchos::Ptr<CompositeVector>& f, bool negate);

  // -- diffusion of temperature
  virtual void ApplyDiffusion_(const Teuchos::Ptr<State>& S,
          const Teuchos::Ptr<CompositeVector>& f);

 protected:
  enum FluxUpdateMode {
    UPDATE_FLUX_ITERATION = 0,
    UPDATE_FLUX_TIMESTEP = 1,
    UPDATE_FLUX_VIS = 2,
    UPDATE_FLUX_NEVER = 3
  };

  int niter_;

  // boundary conditions
  Teuchos::RCP<Functions::BoundaryFunction> bc_temperature_;
  Teuchos::RCP<Functions::BoundaryFunction> bc_flux_;

  // operators
  Operators::UpwindMethod Krel_method_;
  Teuchos::RCP<Operators::Upwinding> upwinding_;

  Teuchos::RCP<Operators::Advection> advection_;
  Teuchos::RCP<Operators::MatrixMFD> matrix_;
  // note PC is in PKPhysicalBDFBase

  // custom enorm tolerances
  double flux_tol_;

  // flags and control
  double dT_max_;
  FluxUpdateMode update_flux_;
  bool modify_predictor_with_consistent_faces_;
  bool is_source_term_;
  bool is_mass_source_term_;
  bool explicit_advection_;
  int explicit_advection_iter_;
  bool precon_used_;

  bool coupled_to_subsurface_via_temp_;
  bool coupled_to_subsurface_via_flux_;
  bool coupled_to_surface_via_temp_;
  bool coupled_to_surface_via_flux_;

  // Keys
  Key energy_key_;
  Key cell_vol_key_;
  Key enthalpy_key_;
  Key flux_key_;
  Key energy_flux_key_;
  Key conductivity_key_;
  Key uw_conductivity_key_;
  Key de_dT_key_;
  Key source_key_;
  Key dsource_dT_key_;
  Key mass_source_key_;

};

} // namespace Energy
} // namespace Amanzi

#endif
<commit_msg>allows accessor for advection to allow advective term in PC<commit_after>/* -*-  mode: c++; c-default-style: "google"; indent-tabs-mode: nil -*- */

/* -------------------------------------------------------------------------
ATS

License: see $ATS_DIR/COPYRIGHT
Author: Ethan Coon

Base energy PK.

This provides the base of an advection-diffusion equation for energy.

------------------------------------------------------------------------- */

#ifndef PKS_ENERGY_BASE_HH_
#define PKS_ENERGY_BASE_HH_

#include "pk_factory.hh"
#include "MatrixMFD.hh"
#include "pk_physical_bdf_base.hh"
#include "upwinding.hh"

namespace Amanzi {

// forward declarations
namespace Operators { class Advection; }
namespace Functions { class BoundaryFunction; }

namespace Energy {

class EnergyBase : public PKPhysicalBDFBase {

public:
  EnergyBase(const Teuchos::RCP<Teuchos::ParameterList>& plist,
             Teuchos::ParameterList& FElist,
             const Teuchos::RCP<TreeVector>& solution) :
      PKDefaultBase(plist, FElist, solution),
      PKPhysicalBDFBase(plist, FElist, solution),
      modify_predictor_with_consistent_faces_(false),
      coupled_to_subsurface_via_temp_(false),
      coupled_to_subsurface_via_flux_(false),
      coupled_to_surface_via_temp_(false),
      coupled_to_surface_via_flux_(false),
      niter_(0),
      explicit_advection_(false) {}

  // Virtual destructor
  virtual ~EnergyBase() {}

  // EnergyBase is a PK
  // -- Setup data
  virtual void setup(const Teuchos::Ptr<State>& S);

  // -- Initialize owned (dependent) variables.
  virtual void initialize(const Teuchos::Ptr<State>& S);

  // -- Commit any secondary (dependent) variables.
  virtual void commit_state(double dt, const Teuchos::RCP<State>& S);

  // -- Calculate any diagnostics prior to doing vis
  virtual void calculate_diagnostics(const Teuchos::RCP<State>& S) {}

  // EnergyBase is a BDFFnBase
  // computes the non-linear functional f = f(t,u,udot)
  virtual void Functional(double t_old, double t_new, Teuchos::RCP<TreeVector> u_old,
                   Teuchos::RCP<TreeVector> u_new, Teuchos::RCP<TreeVector> f);

  // applies preconditioner to u and returns the result in Pu
  virtual void ApplyPreconditioner(Teuchos::RCP<const TreeVector> u, Teuchos::RCP<TreeVector> Pu);

  // updates the preconditioner
  virtual void UpdatePreconditioner(double t, Teuchos::RCP<const TreeVector> up, double h);

  // problems with temperatures -- setting a range of admissible temps
  virtual bool IsAdmissible(Teuchos::RCP<const TreeVector> up);

  // error monitor
  virtual double ErrorNorm(Teuchos::RCP<const TreeVector> u,
                       Teuchos::RCP<const TreeVector> du);

  virtual bool ModifyPredictor(double h, Teuchos::RCP<const TreeVector> u0,
          Teuchos::RCP<TreeVector> u);

  // evaluating consistent faces for given BCs and cell values
  virtual void CalculateConsistentFaces(const Teuchos::Ptr<CompositeVector>& u);

  Teuchos::RCP<Operators::Advection>& advection() { return advection_; }

protected:
  // These must be provided by the deriving PK.
  // -- setup the evaluators
  virtual void SetupPhysicalEvaluators_(const Teuchos::Ptr<State>& S) = 0;

  // -- get enthalpy as a function of Dirichlet boundary data.  Note that this
  //    will get replaced by a better system when we get maps on the boundary
  //    faces.
  virtual void ApplyDirichletBCsToEnthalpy_(const Teuchos::Ptr<State>& S,
          const Teuchos::Ptr<CompositeVector>& enth) = 0;

  // -- Add any source terms into the residual.
  virtual void AddSources_(const Teuchos::Ptr<State>& S,
                           const Teuchos::Ptr<CompositeVector>& f);
  virtual void AddSourcesToPrecon_(const Teuchos::Ptr<State>& S, double h);

  // Standard methods
  virtual void SetupEnergy_(const Teuchos::Ptr<State>& S);

  // Upwinding conductivities
  virtual bool UpdateConductivityData_(const Teuchos::Ptr<State>& S);

  // boundary condition members
  virtual void UpdateBoundaryConditions_();
  virtual void ApplyBoundaryConditions_(const Teuchos::RCP<CompositeVector>& temperature);

  // physical methods
  // -- accumulation of energy
  virtual void AddAccumulation_(const Teuchos::Ptr<CompositeVector>& f);

  // -- advection of enthalpy
  virtual void AddAdvection_(const Teuchos::Ptr<State>& S,
                     const Teuchos::Ptr<CompositeVector>& f, bool negate);

  // -- diffusion of temperature
  virtual void ApplyDiffusion_(const Teuchos::Ptr<State>& S,
          const Teuchos::Ptr<CompositeVector>& f);

 protected:
  enum FluxUpdateMode {
    UPDATE_FLUX_ITERATION = 0,
    UPDATE_FLUX_TIMESTEP = 1,
    UPDATE_FLUX_VIS = 2,
    UPDATE_FLUX_NEVER = 3
  };

  int niter_;

  // boundary conditions
  Teuchos::RCP<Functions::BoundaryFunction> bc_temperature_;
  Teuchos::RCP<Functions::BoundaryFunction> bc_flux_;

  // operators
  Operators::UpwindMethod Krel_method_;
  Teuchos::RCP<Operators::Upwinding> upwinding_;

  Teuchos::RCP<Operators::Advection> advection_;
  Teuchos::RCP<Operators::MatrixMFD> matrix_;
  // note PC is in PKPhysicalBDFBase

  // custom enorm tolerances
  double flux_tol_;

  // flags and control
  double dT_max_;
  FluxUpdateMode update_flux_;
  bool modify_predictor_with_consistent_faces_;
  bool is_source_term_;
  bool is_mass_source_term_;
  bool explicit_advection_;
  int explicit_advection_iter_;
  bool precon_used_;

  bool coupled_to_subsurface_via_temp_;
  bool coupled_to_subsurface_via_flux_;
  bool coupled_to_surface_via_temp_;
  bool coupled_to_surface_via_flux_;

  // Keys
  Key energy_key_;
  Key cell_vol_key_;
  Key enthalpy_key_;
  Key flux_key_;
  Key energy_flux_key_;
  Key conductivity_key_;
  Key uw_conductivity_key_;
  Key de_dT_key_;
  Key source_key_;
  Key dsource_dT_key_;
  Key mass_source_key_;

};

} // namespace Energy
} // namespace Amanzi

#endif
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestBarChartActor.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// This tests the spider plot capabilities in VTK.
#include "vtkBarChartActor.h"
#include "vtkFloatArray.h"
#include "vtkDataObject.h"
#include "vtkFieldData.h"
#include "vtkMath.h"
#include "vtkTextProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPolyData.h"
#include "vtkPoints.h"
#include "vtkIdList.h"
#include "vtkProperty2D.h"
#include "vtkLegendBoxActor.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"

//----------------------------------------------------------------------------
int TestBarChartActor( int argc, char * argv [] )
{
  int numTuples = 6;

  vtkFloatArray *bitter = vtkFloatArray::New();
  bitter->SetNumberOfTuples(numTuples);

  for (int i=0; i<numTuples; i++)
    {
    bitter->SetTuple1(i, vtkMath::Random(7,100));
    }

  vtkDataObject *dobj = vtkDataObject::New();
  dobj->GetFieldData()->AddArray(bitter);

  vtkBarChartActor *actor = vtkBarChartActor::New();
  actor->SetInput(dobj);
  actor->SetTitle("Bar Chart");
  actor->GetPositionCoordinate()->SetValue(0.05,0.05,0.0);
  actor->GetPosition2Coordinate()->SetValue(0.95,0.85,0.0);
  actor->GetProperty()->SetColor(1,1,1);
  actor->GetLegendActor()->SetNumberOfEntries(numTuples);
  for (int i=0; i<numTuples; i++)
    {
    actor->SetBarColor(i, vtkMath::Random(0,1), vtkMath::Random(0,1),
                         vtkMath::Random(0,1));
    }
  actor->SetBarLabel(0,"oil");
  actor->SetBarLabel(1,"gas");
  actor->SetBarLabel(2,"water");
  actor->SetBarLabel(3,"snake oil");
  actor->SetBarLabel(4,"tequila");
  actor->SetBarLabel(5,"beer");
  actor->LegendVisibilityOn();

  // Set text colors (same as actor for backward compat with test)
  actor->GetTitleTextProperty()->SetColor(1,1,0);
  actor->GetLabelTextProperty()->SetColor(1,0,0);

  // Create the RenderWindow, Renderer and both Actors
  vtkRenderer *ren1 = vtkRenderer::New();
  vtkRenderWindow *renWin = vtkRenderWindow::New();
  renWin->AddRenderer(ren1);
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
  iren->SetRenderWindow(renWin);

  ren1->AddActor(actor);
  ren1->SetBackground(0,0,0);
  renWin->SetSize(500,200);

  // render the image
  renWin->Render();

  int retVal = vtkRegressionTestImage( renWin );
  if ( retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Start();
    }

  bitter->Delete();
  dobj->Delete();
  actor->Delete();
  ren1->Delete();
  renWin->Delete();
  iren->Delete();

  return !retVal;
}
<commit_msg>ENH:Display the seed value at the beginning of the test. Just to see if it is different on some platform since this test is failing on some platform or maybe static/shared lib, etc. It should be 1177 (initial value).<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestBarChartActor.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// This tests the spider plot capabilities in VTK.
#include "vtkBarChartActor.h"
#include "vtkFloatArray.h"
#include "vtkDataObject.h"
#include "vtkFieldData.h"
#include "vtkMath.h"
#include "vtkTextProperty.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPolyData.h"
#include "vtkPoints.h"
#include "vtkIdList.h"
#include "vtkProperty2D.h"
#include "vtkLegendBoxActor.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"

//----------------------------------------------------------------------------
int TestBarChartActor( int argc, char * argv [] )
{
  int numTuples = 6;

  vtkFloatArray *bitter = vtkFloatArray::New();
  bitter->SetNumberOfTuples(numTuples);

  cout << "Seed=" << vtkMath::GetSeed() << endl;

  for (int i=0; i<numTuples; i++)
    {
    bitter->SetTuple1(i, vtkMath::Random(7,100));
    }

  vtkDataObject *dobj = vtkDataObject::New();
  dobj->GetFieldData()->AddArray(bitter);

  vtkBarChartActor *actor = vtkBarChartActor::New();
  actor->SetInput(dobj);
  actor->SetTitle("Bar Chart");
  actor->GetPositionCoordinate()->SetValue(0.05,0.05,0.0);
  actor->GetPosition2Coordinate()->SetValue(0.95,0.85,0.0);
  actor->GetProperty()->SetColor(1,1,1);
  actor->GetLegendActor()->SetNumberOfEntries(numTuples);
  for (int i=0; i<numTuples; i++)
    {
    actor->SetBarColor(i, vtkMath::Random(0,1), vtkMath::Random(0,1),
                         vtkMath::Random(0,1));
    }
  actor->SetBarLabel(0,"oil");
  actor->SetBarLabel(1,"gas");
  actor->SetBarLabel(2,"water");
  actor->SetBarLabel(3,"snake oil");
  actor->SetBarLabel(4,"tequila");
  actor->SetBarLabel(5,"beer");
  actor->LegendVisibilityOn();

  // Set text colors (same as actor for backward compat with test)
  actor->GetTitleTextProperty()->SetColor(1,1,0);
  actor->GetLabelTextProperty()->SetColor(1,0,0);

  // Create the RenderWindow, Renderer and both Actors
  vtkRenderer *ren1 = vtkRenderer::New();
  vtkRenderWindow *renWin = vtkRenderWindow::New();
  renWin->AddRenderer(ren1);
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
  iren->SetRenderWindow(renWin);

  ren1->AddActor(actor);
  ren1->SetBackground(0,0,0);
  renWin->SetSize(500,200);

  // render the image
  renWin->Render();

  int retVal = vtkRegressionTestImage( renWin );
  if ( retVal == vtkRegressionTester::DO_INTERACTOR)
    {
    iren->Start();
    }

  bitter->Delete();
  dobj->Delete();
  actor->Delete();
  ren1->Delete();
  renWin->Delete();
  iren->Delete();

  return !retVal;
}
<|endoftext|>


<commit_before>#include "GameController.h"

#include "AudioProcessor.h"

#include <QThread>

extern "C" {
#include "gba.h"
#include "gba-audio.h"
#include "gba-serialize.h"
#include "renderers/video-software.h"
#include "util/vfs.h"
}

using namespace QGBA;

GameController::GameController(QObject* parent)
	: QObject(parent)
	, m_drawContext(new uint32_t[256 * 256])
	, m_threadContext()
	, m_activeKeys(0)
	, m_gameOpen(false)
	, m_audioThread(new QThread(this))
	, m_audioProcessor(new AudioProcessor)
{
	m_renderer = new GBAVideoSoftwareRenderer;
	GBAVideoSoftwareRendererCreate(m_renderer);
	m_renderer->outputBuffer = (color_t*) m_drawContext;
	m_renderer->outputBufferStride = 256;
	m_threadContext.state = THREAD_INITIALIZED;
	m_threadContext.debugger = 0;
	m_threadContext.frameskip = 0;
	m_threadContext.bios = 0;
	m_threadContext.renderer = &m_renderer->d;
	m_threadContext.userData = this;
	m_threadContext.rewindBufferCapacity = 0;
	m_threadContext.logLevel = -1;

	GBAInputMapInit(&m_threadContext.inputMap);

#ifdef BUILD_SDL
	SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
	m_sdlEvents.bindings = &m_threadContext.inputMap;
	GBASDLInitEvents(&m_sdlEvents);
	SDL_JoystickEventState(SDL_QUERY);
#endif

	m_threadContext.startCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_audioProcessor->setInput(context);
		controller->gameStarted(context);
	};

	m_threadContext.cleanCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->gameStopped(context);
	};

	m_threadContext.frameCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_pauseMutex.lock();
		if (controller->m_pauseAfterFrame) {
			GBAThreadPauseFromThread(context);
			controller->m_pauseAfterFrame = false;
			controller->gamePaused(&controller->m_threadContext);
		}
		controller->m_pauseMutex.unlock();
		controller->frameAvailable(controller->m_drawContext);
	};

	m_threadContext.logHandler = [] (GBAThread* context, enum GBALogLevel level, const char* format, va_list args) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->postLog(level, QString().vsprintf(format, args));
	};

	m_audioThread->start(QThread::TimeCriticalPriority);
	m_audioProcessor->moveToThread(m_audioThread);
	connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start()));
	connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start()));

#ifdef BUILD_SDL
	connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(testSDLEvents()));
#endif
}

GameController::~GameController() {
	m_audioThread->quit();
	m_audioThread->wait();
	if (GBAThreadIsPaused(&m_threadContext)) {
		GBAThreadUnpause(&m_threadContext);
	}
	disconnect();
	closeGame();
	delete m_renderer;
}

ARMDebugger* GameController::debugger() {
	return m_threadContext.debugger;
}

void GameController::setDebugger(ARMDebugger* debugger) {
	bool wasPaused = isPaused();
	setPaused(true);
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBADetachDebugger(m_threadContext.gba);
	}
	m_threadContext.debugger = debugger;
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBAAttachDebugger(m_threadContext.gba, m_threadContext.debugger);
	}
	setPaused(wasPaused);
}

void GameController::loadGame(const QString& path, bool dirmode) {
	closeGame();
	m_threadContext.sync.videoFrameWait = 0;
	m_threadContext.sync.audioWait = 1;
	if (!dirmode) {
		QFile file(path);
		if (!file.open(QIODevice::ReadOnly)) {
			return;
		}
		file.close();
	}
	m_gameOpen = true;

	m_pauseAfterFrame = false;

	m_threadContext.fname = strdup(path.toLocal8Bit().constData());
	if (dirmode) {
		m_threadContext.gameDir = VDirOpen(m_threadContext.fname);
		m_threadContext.stateDir = m_threadContext.gameDir;
	} else {
		m_threadContext.rom = VFileOpen(m_threadContext.fname, O_RDONLY);
#if ENABLE_LIBZIP
		m_threadContext.gameDir = VDirOpenZip(m_threadContext.fname, 0);
#endif
	}

	if (!m_bios.isNull()) {
		m_threadContext.bios = VFileOpen(m_bios.toLocal8Bit().constData(), O_RDONLY);
	}

	GBAThreadStart(&m_threadContext);
}

void GameController::loadBIOS(const QString& path) {
	m_bios = path;
}

void GameController::closeGame() {
	if (!m_gameOpen) {
		return;
	}
	GBAThreadEnd(&m_threadContext);
	GBAThreadJoin(&m_threadContext);
	if (m_threadContext.fname) {
		free(const_cast<char*>(m_threadContext.fname));
		m_threadContext.fname = nullptr;
	}

	m_gameOpen = false;
	emit gameStopped(&m_threadContext);
}

bool GameController::isPaused() {
	return GBAThreadIsPaused(&m_threadContext);
}

void GameController::setPaused(bool paused) {
	if (paused == GBAThreadIsPaused(&m_threadContext)) {
		return;
	}
	if (paused) {
		GBAThreadPause(&m_threadContext);
		emit gamePaused(&m_threadContext);
	} else {
		GBAThreadUnpause(&m_threadContext);
		emit gameUnpaused(&m_threadContext);
	}
}

void GameController::reset() {
	GBAThreadReset(&m_threadContext);
}

void GameController::frameAdvance() {
	m_pauseMutex.lock();
	m_pauseAfterFrame = true;
	setPaused(false);
	m_pauseMutex.unlock();
}

void GameController::keyPressed(int key) {
	int mappedKey = 1 << key;
	m_activeKeys |= mappedKey;
	updateKeys();
}

void GameController::keyReleased(int key) {
	int mappedKey = 1 << key;
	m_activeKeys &= ~mappedKey;
	updateKeys();
}

void GameController::setAudioBufferSamples(int samples) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.audioBuffers = samples;
	GBAAudioResizeBuffer(&m_threadContext.gba->audio, samples);
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples));
}

void GameController::setFPSTarget(float fps) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.fpsTarget = fps;
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged");
}

void GameController::loadState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBALoadState(m_threadContext.gba, m_threadContext.stateDir, slot);
	GBAThreadContinue(&m_threadContext);
	emit stateLoaded(&m_threadContext);
	emit frameAvailable(m_drawContext);
}

void GameController::saveState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBASaveState(m_threadContext.gba, m_threadContext.stateDir, slot, true);
	GBAThreadContinue(&m_threadContext);
}

void GameController::updateKeys() {
	int activeKeys = m_activeKeys;
#ifdef BUILD_SDL
	activeKeys |= m_activeButtons;
#endif
	m_threadContext.activeKeys = activeKeys;
}

#ifdef BUILD_SDL
void GameController::testSDLEvents() {
	SDL_Joystick* joystick = m_sdlEvents.joystick;
	SDL_JoystickUpdate();
	int numButtons = SDL_JoystickNumButtons(joystick);
	m_activeButtons = 0;
	int i;
	for (i = 0; i < numButtons; ++i) {
		GBAKey key = GBAInputMapKey(&m_threadContext.inputMap, SDL_BINDING_BUTTON, i);
		if (key == GBA_KEY_NONE) {
			continue;
		}
		if (SDL_JoystickGetButton(joystick, i)) {
			m_activeButtons |= 1 << key;
		}
	}
	int numHats = SDL_JoystickNumHats(joystick);
	for (i = 0; i < numHats; ++i) {
		int hat = SDL_JoystickGetHat(joystick, i);
		if (hat & SDL_HAT_UP) {
			m_activeButtons |= 1 << GBA_KEY_UP;
		}
		if (hat & SDL_HAT_LEFT) {
			m_activeButtons |= 1 << GBA_KEY_LEFT;
		}
		if (hat & SDL_HAT_DOWN) {
			m_activeButtons |= 1 << GBA_KEY_DOWN;
		}
		if (hat & SDL_HAT_RIGHT) {
			m_activeButtons |= 1 << GBA_KEY_RIGHT;
		}
	}
	updateKeys();
}
#endif
<commit_msg>Don't initialize SDL video in Qt port<commit_after>#include "GameController.h"

#include "AudioProcessor.h"

#include <QThread>

extern "C" {
#include "gba.h"
#include "gba-audio.h"
#include "gba-serialize.h"
#include "renderers/video-software.h"
#include "util/vfs.h"
}

using namespace QGBA;

GameController::GameController(QObject* parent)
	: QObject(parent)
	, m_drawContext(new uint32_t[256 * 256])
	, m_threadContext()
	, m_activeKeys(0)
	, m_gameOpen(false)
	, m_audioThread(new QThread(this))
	, m_audioProcessor(new AudioProcessor)
{
	m_renderer = new GBAVideoSoftwareRenderer;
	GBAVideoSoftwareRendererCreate(m_renderer);
	m_renderer->outputBuffer = (color_t*) m_drawContext;
	m_renderer->outputBufferStride = 256;
	m_threadContext.state = THREAD_INITIALIZED;
	m_threadContext.debugger = 0;
	m_threadContext.frameskip = 0;
	m_threadContext.bios = 0;
	m_threadContext.renderer = &m_renderer->d;
	m_threadContext.userData = this;
	m_threadContext.rewindBufferCapacity = 0;
	m_threadContext.logLevel = -1;

	GBAInputMapInit(&m_threadContext.inputMap);

#ifdef BUILD_SDL
	SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
	m_sdlEvents.bindings = &m_threadContext.inputMap;
	GBASDLInitEvents(&m_sdlEvents);
	SDL_JoystickEventState(SDL_QUERY);
#endif

	m_threadContext.startCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_audioProcessor->setInput(context);
		controller->gameStarted(context);
	};

	m_threadContext.cleanCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->gameStopped(context);
	};

	m_threadContext.frameCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_pauseMutex.lock();
		if (controller->m_pauseAfterFrame) {
			GBAThreadPauseFromThread(context);
			controller->m_pauseAfterFrame = false;
			controller->gamePaused(&controller->m_threadContext);
		}
		controller->m_pauseMutex.unlock();
		controller->frameAvailable(controller->m_drawContext);
	};

	m_threadContext.logHandler = [] (GBAThread* context, enum GBALogLevel level, const char* format, va_list args) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->postLog(level, QString().vsprintf(format, args));
	};

	m_audioThread->start(QThread::TimeCriticalPriority);
	m_audioProcessor->moveToThread(m_audioThread);
	connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start()));
	connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start()));

#ifdef BUILD_SDL
	connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(testSDLEvents()));
#endif
}

GameController::~GameController() {
	m_audioThread->quit();
	m_audioThread->wait();
	if (GBAThreadIsPaused(&m_threadContext)) {
		GBAThreadUnpause(&m_threadContext);
	}
	disconnect();
	closeGame();
	delete m_renderer;
}

ARMDebugger* GameController::debugger() {
	return m_threadContext.debugger;
}

void GameController::setDebugger(ARMDebugger* debugger) {
	bool wasPaused = isPaused();
	setPaused(true);
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBADetachDebugger(m_threadContext.gba);
	}
	m_threadContext.debugger = debugger;
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBAAttachDebugger(m_threadContext.gba, m_threadContext.debugger);
	}
	setPaused(wasPaused);
}

void GameController::loadGame(const QString& path, bool dirmode) {
	closeGame();
	m_threadContext.sync.videoFrameWait = 0;
	m_threadContext.sync.audioWait = 1;
	if (!dirmode) {
		QFile file(path);
		if (!file.open(QIODevice::ReadOnly)) {
			return;
		}
		file.close();
	}
	m_gameOpen = true;

	m_pauseAfterFrame = false;

	m_threadContext.fname = strdup(path.toLocal8Bit().constData());
	if (dirmode) {
		m_threadContext.gameDir = VDirOpen(m_threadContext.fname);
		m_threadContext.stateDir = m_threadContext.gameDir;
	} else {
		m_threadContext.rom = VFileOpen(m_threadContext.fname, O_RDONLY);
#if ENABLE_LIBZIP
		m_threadContext.gameDir = VDirOpenZip(m_threadContext.fname, 0);
#endif
	}

	if (!m_bios.isNull()) {
		m_threadContext.bios = VFileOpen(m_bios.toLocal8Bit().constData(), O_RDONLY);
	}

	GBAThreadStart(&m_threadContext);
}

void GameController::loadBIOS(const QString& path) {
	m_bios = path;
}

void GameController::closeGame() {
	if (!m_gameOpen) {
		return;
	}
	GBAThreadEnd(&m_threadContext);
	GBAThreadJoin(&m_threadContext);
	if (m_threadContext.fname) {
		free(const_cast<char*>(m_threadContext.fname));
		m_threadContext.fname = nullptr;
	}

	m_gameOpen = false;
	emit gameStopped(&m_threadContext);
}

bool GameController::isPaused() {
	return GBAThreadIsPaused(&m_threadContext);
}

void GameController::setPaused(bool paused) {
	if (paused == GBAThreadIsPaused(&m_threadContext)) {
		return;
	}
	if (paused) {
		GBAThreadPause(&m_threadContext);
		emit gamePaused(&m_threadContext);
	} else {
		GBAThreadUnpause(&m_threadContext);
		emit gameUnpaused(&m_threadContext);
	}
}

void GameController::reset() {
	GBAThreadReset(&m_threadContext);
}

void GameController::frameAdvance() {
	m_pauseMutex.lock();
	m_pauseAfterFrame = true;
	setPaused(false);
	m_pauseMutex.unlock();
}

void GameController::keyPressed(int key) {
	int mappedKey = 1 << key;
	m_activeKeys |= mappedKey;
	updateKeys();
}

void GameController::keyReleased(int key) {
	int mappedKey = 1 << key;
	m_activeKeys &= ~mappedKey;
	updateKeys();
}

void GameController::setAudioBufferSamples(int samples) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.audioBuffers = samples;
	GBAAudioResizeBuffer(&m_threadContext.gba->audio, samples);
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples));
}

void GameController::setFPSTarget(float fps) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.fpsTarget = fps;
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged");
}

void GameController::loadState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBALoadState(m_threadContext.gba, m_threadContext.stateDir, slot);
	GBAThreadContinue(&m_threadContext);
	emit stateLoaded(&m_threadContext);
	emit frameAvailable(m_drawContext);
}

void GameController::saveState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBASaveState(m_threadContext.gba, m_threadContext.stateDir, slot, true);
	GBAThreadContinue(&m_threadContext);
}

void GameController::updateKeys() {
	int activeKeys = m_activeKeys;
#ifdef BUILD_SDL
	activeKeys |= m_activeButtons;
#endif
	m_threadContext.activeKeys = activeKeys;
}

#ifdef BUILD_SDL
void GameController::testSDLEvents() {
	SDL_Joystick* joystick = m_sdlEvents.joystick;
	SDL_JoystickUpdate();
	int numButtons = SDL_JoystickNumButtons(joystick);
	m_activeButtons = 0;
	int i;
	for (i = 0; i < numButtons; ++i) {
		GBAKey key = GBAInputMapKey(&m_threadContext.inputMap, SDL_BINDING_BUTTON, i);
		if (key == GBA_KEY_NONE) {
			continue;
		}
		if (SDL_JoystickGetButton(joystick, i)) {
			m_activeButtons |= 1 << key;
		}
	}
	int numHats = SDL_JoystickNumHats(joystick);
	for (i = 0; i < numHats; ++i) {
		int hat = SDL_JoystickGetHat(joystick, i);
		if (hat & SDL_HAT_UP) {
			m_activeButtons |= 1 << GBA_KEY_UP;
		}
		if (hat & SDL_HAT_LEFT) {
			m_activeButtons |= 1 << GBA_KEY_LEFT;
		}
		if (hat & SDL_HAT_DOWN) {
			m_activeButtons |= 1 << GBA_KEY_DOWN;
		}
		if (hat & SDL_HAT_RIGHT) {
			m_activeButtons |= 1 << GBA_KEY_RIGHT;
		}
	}
	updateKeys();
}
#endif
<|endoftext|>